Calculate date in SQL Query - sql

I am trying to calculate a date within an SQL query which is the date_required add the number of days in despatchdate - I am currently getting the error Invalid column name 'despatchdays'. If the despatchdays is null or "" then I want it to default to -14.
SELECT order_no, order_line_no, currency, product, address1,description, date_required,
(SELECT despatchdays
FROM scheme.PDBtblSuppliers
WHERE SupplierIDFK = dbo.qryArrears2.supplier) AS despatchdays,
DATEADD(d, despatchdays, date_required) AS despatchdate
FROM dbo.qryArrears2
How can I optimise this to get it working ?
I am using SQL 2000.

You can use:
SELECT order_no
, order_line_no
, currency
, product
, address1
,description
, date_required
, DATEADD(day, coalesce(pd.despatchdays, -14), date_required) AS despatchdate
FROM dbo.qryArrears2 qa
INNER JOIN scheme.PDBtblSuppliers pd On pd.SupplierIDFK = qa.supplier
But it may give you more rows if there are several rows in PDBtblSuppliers for a supplier in qryArrears2.
You can also move despatchdate query inside the DATEADD:
SELECT * FROM (
SELECT order_no
, order_line_no
, currency
, product
, address1
, description
, date_required
, DATEADD(day
, coalesce((SELECT despatchdays FROM scheme.PDBtblSuppliers WHERE SupplierIDFK = qa.supplier), -14)
, date_required
) AS despatchdate
FROM dbo.qryArrears2 qa
) as d
WHERE despatchdate = '20150101'
coalesce(despatchdays, -14) will replace despatchdays by -14 if despatchdays is NULL.
If date_required is a (var)char, you should replace it by a date in your table or cast is to data(time): CAST(date_required as date)

Can't you just JOIN the table and then use it like this:
SELECT
order_no,
order_line_no,
currency,
product,
address1,
description,
date_required,
despatchdays,
DATEADD(d, despatchdays, date_required) AS despatchdate
FROM
dbo.qryArrears2
JOIN scheme.PDBtblSuppliers
ON SupplierIDFK = dbo.qryArrears2.supplier
Update:
You can cast the date_required to a datetime like this:
CAST(date_required AS DATETIME)

Related

Total customer per reporting date without union

I would like to display to run this report where I show the total number of customers per reporting date. Here is a how I need the data to look like:
My original dataset look like this (please see query): In order to calculate the number of customers. I need to use the start and end date: if Start_Date>reporting_date and End_Date<=reporting_date then count as a customer.
I was able to develop a script, but it only gives me the total number of customers for only one reporting date.
select '2022-10-31' reporting_date, count(case when Start_Date>'2022-10-31' and End_Date<='2022-10-31' then Customer_ID end)
from (values ('2022-10-14','2022-8-19','0010Y654012P6KuQAK')
, ('2022-3-15','2022-9-14','0011v65402PoSpVAAV')
, ('2021-1-11','2022-10-11','0010Y654012P6DuQAK')
, ('2022-12-1','2022-5-14','0011v65402u7muLAAQ')
, ('2021-1-30','2022-3-14','0010Y654012P6DuQAK')
, ('2022-10-31','2022-2-14','0010Y654012P6PJQA0')
, ('2021-10-31','US','0010Y654012P6PJQA0')
, ('2021-5-31','2022-5-14','0011v65402x8cjqAAA')
, ('2022-6-2','2022-1-13','0010Y654016OqkJQAS')
, ('2022-1-1','2022-11-11','0010Y654016OqIaQAK')
) a(Start_Date ,End_Date ,Customer_ID)
Is there a way to amend the code with cross-join or other workarounds to the total customers per reporting date without doing many unions
select '2022-10-31' reporting_date, count(case when Start_Date>'2022-10-31' and End_Date<='2022-10-31' then Customer_ID end)
from (values ('2022-10-14','2022-8-19','0010Y654012P6KuQAK')
, ('2022-3-15','2022-9-14','0011v65402PoSpVAAV')
, ('2021-1-11','2022-10-11','0010Y654012P6DuQAK')
, ('2022-12-1','2022-5-14','0011v65402u7muLAAQ')
, ('2021-1-30','2022-3-14','0010Y654012P6DuQAK')
, ('2022-10-31','2022-2-14','0010Y654012P6PJQA0')
, ('2021-10-31','US','0010Y654012P6PJQA0')
, ('2021-5-31','2022-5-14','0011v65402x8cjqAAA')
, ('2022-6-2','2022-1-13','0010Y654016OqkJQAS')
, ('2022-1-1','2022-11-11','0010Y654016OqIaQAK')
) a(Start_Date ,End_Date ,Customer_ID)
UNION ALL
select '2022-9-30' reporting_date, count(case when Start_Date>'2022-9-301' and End_Date<='2022-9-30' then Customer_ID end)
from (values ('2022-10-14','2022-8-19','0010Y654012P6KuQAK')
, ('2022-3-15','2022-9-14','0011v65402PoSpVAAV')
, ('2021-1-11','2022-10-11','0010Y654012P6DuQAK')
, ('2022-12-1','2022-5-14','0011v65402u7muLAAQ')
, ('2021-1-30','2022-3-14','0010Y654012P6DuQAK')
, ('2022-10-31','2022-2-14','0010Y654012P6PJQA0')
, ('2021-10-31','US','0010Y654012P6PJQA0')
, ('2021-5-31','2022-5-14','0011v65402x8cjqAAA')
, ('2022-6-2','2022-1-13','0010Y654016OqkJQAS')
, ('2022-1-1','2022-11-11','0010Y654016OqIaQAK')
) a(Start_Date ,End_Date ,Customer_ID)
It is possible to provide date ranges as a separate table/subquery, join to the actual data and perform grouping:
select s.start_d, s.end_d, COUNT(Customer_ID) AS total
FROM (SELECT '2022-10-31'::DATE, '2022-10-31'::DATE
UNION SELECT '2022-09-30', '2022-09-30')
AS s(start_d, end_d)
LEFT JOIN (values ('2022-10-14','2022-8-19','0010Y654012P6KuQAK')
, ('2022-3-15','2022-9-14','0011v65402PoSpVAAV')
, ('2021-1-11','2022-10-11','0010Y654012P6DuQAK')
, ('2022-12-1','2022-5-14','0011v65402u7muLAAQ')
, ('2021-1-30','2022-3-14','0010Y654012P6DuQAK')
, ('2022-10-31','2022-2-14','0010Y654012P6PJQA0')
, ('2021-10-31','2021-10-31','0010Y654012P6PJQA0')
, ('2021-5-31','2022-5-14','0011v65402x8cjqAAA')
, ('2022-6-2','2022-1-13','0010Y654016OqkJQAS')
, ('2022-1-1','2022-11-11','0010Y654016OqIaQAK')
) a(Start_Date ,End_Date ,Customer_ID)
ON a.Start_Date>s.start_d and a.End_Date<=s.end_d
GROUP BY s.start_d, s.end_d;
Output:

Performance issue using IsNull function in the Select statement

I have a financial application. I have ViewHistoricInstrumentValue which has rows like this
instrument1, date1, price, grossValue, netValue
instrument2, date1, price, grossValue, netValue
...
instrument1, date2, price, grossValue, netValue
...
My views are complicated but the db itself is small (4000 transactions). ViewHistoricInstrumentValue was executed in less than 1 second before I added the next CTE to the view. After that it takes 26s. ActualEvaluationPrice is the price for instrumentX at dateY. If this value is missing from HistoricPrice table then I find the previous price for instrumentX.
, UsedEvaluationPriceCte AS (
SELECT *
, isnull(ActualEvaluationPrice,
(select top 1 HistoricPrice.Price -- PreviousPrice
from HistoricPrice JOIN ValidDate
on HistoricPrice.DateId = ValidDate.Id
and HistoricPrice.InstrumentId = StartingCte.InstrumentId
and ValidDate.[Date] < StartingCte.DateValue
order by ValidDate.[Date]))
as UsedEvaluationPrice
FROM StartingCte
)
My problem is that the execution time increased needlessly. Right now the HistoricPrice table has no missing value so ActualEvaluationPrice is never null, so the previous price should be never determined.
ViewHistoricInstrumentValue returns 1815 rows. One other mystery is that the first query takes 26s, but the second only 2s.
SELECT * FROM [ViewHistoricInstrumentValue]
SELECT top(2000) * FROM [ViewHistoricInstrumentValue]
Appendix
The execution plan: https://www.dropbox.com/s/5st69uhjkpd3b5y/IsNull.sqlplan?dl=0
The same plan: https://www.brentozar.com/pastetheplan/?id=rk9bK1Wiv
The view:
ALTER VIEW [dbo].[ViewHistoricInstrumentValue] AS
WITH StartingCte AS (
SELECT
HistoricInstrumentValue.DateId
, ValidDate.Date as DateValue
, TransactionId
, TransactionId AS [Row]
, AccountId
, AccountName
, ViewTransaction.InstrumentId
, ViewTransaction.InstrumentName
, OpeningDate
, OpeningPrice
, Price AS ActualEvaluationPrice
, ClosingDate
, Amount
, isnull(ViewTransaction.FeeValue, 0) as FeeValue
, HistoricInstrumentValue.Id AS Id
FROM ViewBriefHistoricInstrumentValue as HistoricInstrumentValue
JOIN ValidDate on HistoricInstrumentValue.DateId = ValidDate.Id
JOIN ViewTransaction ON ViewTransaction.Id = HistoricInstrumentValue.TransactionId
left JOIN ViewHistoricPrice ON ViewHistoricPrice.DateId = HistoricInstrumentValue.DateId AND
ViewHistoricPrice.InstrumentId = ViewTransaction.InstrumentId
)
, UsedEvaluationPriceCte AS (
SELECT *
, isnull(ActualEvaluationPrice,
(select top 1 HistoricPrice.Price -- PreviousPrice
from HistoricPrice JOIN ValidDate
on HistoricPrice.DateId = ValidDate.Id
and HistoricPrice.InstrumentId = StartingCte.InstrumentId
and ValidDate.[Date] < StartingCte.DateValue
order by ValidDate.[Date]))
as UsedEvaluationPrice
FROM StartingCte
)
, GrossEvaluationValueCte AS (
SELECT *
, Amount * UsedEvaluationPrice AS GrossEvaluationValue
, (UsedEvaluationPrice - OpeningPrice) * Amount AS GrossCapitalGains
FROM UsedEvaluationPriceCte
)
, CapitalGainsTaxCte AS (
SELECT *
, dbo.MyMax(GrossCapitalGains * 0.15, 0) AS CapitalGainsTax
FROM GrossEvaluationValueCte
)
, IsOpenCte AS (
SELECT
DateId
, DateValue
, TransactionId
, [Row]
, AccountId
, AccountName
, InstrumentId
, InstrumentName
, OpeningDate
, OpeningPrice
, ActualEvaluationPrice
, UsedEvaluationPrice
, ClosingDate
, Amount
, GrossEvaluationValue
, GrossCapitalGains
, CapitalGainsTax
, FeeValue
, GrossEvaluationValue - CapitalGainsTax - FeeValue AS NetEvaluationValue
, GrossCapitalGains - CapitalGainsTax - FeeValue AS NetUnrealizedGains
, CASE WHEN ClosingDate IS NULL OR DateValue < ClosingDate
THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT)
END
AS IsOpen
, convert(NVARCHAR, DateValue, 20) + cast([Id] AS NVARCHAR(MAX)) AS Temp
, Id
FROM CapitalGainsTaxCte
)
Select * from IsOpenCte
I have no idea what your query is supposed to be doing. But this process:
ActualEvaluationPrice is the price for instrumentX at dateY. If this value is missing from HistoricPrice table then I find the previous price for instrumentX.
is handled easily with lag():
select vhiv.*
coalesce(vhiv.ActualEvaluationPrice,
lag(vhiv.ActualEvaluationPrice) over (partition by vhiv.InstrumentId order by DateValue)
) as UsedEvaluationPrice
from ViewHistoricInstrumentValue vhiv;
Note: If you need to filter out certain dates by joining to ValidDates, you can include the JOIN in the query. However, that is not part of the problem statement.

Query that returns date of first and last record for each day within a d

I have a table that records vehicle locations and I wish to query this to get the first and the last record for each vehicle for each day in a date range. The table looks like:
Registration Latitude Longitude dateOfRecord
A1 XBO 123.066 1.456 2019-08-01 00:04:19.000
A1 XBO 128.066 1.436 2019-08-01 22:04:19.000
A1 XBO 118.066 1.456 2019-08-01 23:45:00.000
There are multiple vehicles with three weeks worth of data being held in the table 100,000 records this is written to an archive every night which leaves a 21 days of records which I wish to query. With my sample I would like to get:
Reg Day StartTime StartLat StartLong EndTime EndLat EndLong
A2 XBO 01-08-19 00:04 123.066 1.456 23:45 118.066 1.456
I have an existing query that gets the most recent records but this can't be used for my requirements as it uses the MAX(ID) within the query and I don't believe that you can mix both MAX and MIN in the same query. I could use this as the basis of a table in a stored procedure and then loop through the records and query each to get the first record in the date range but this would be a very resource greedy process! I have included this purely to show what I already have:
SELECT TOP (100) PERCENT m.Registration, m.Location, m.dateoffix,
m.Latitude, m.Longitude, MAX(m.ID) AS ID
FROM dbo.GPSPositions AS m
INNER JOIN
(SELECT Registration AS vr,
MAX(CONVERT(datetime, dateoffix, 103)) AS tdate
FROM dbo.GPSPositions
GROUP BY Registration) AS s ON m.Registration =
s.vr AND CONVERT(datetime, m.dateoffix, 103) = s.tdate
GROUP BY m.Registration, m.Location, m.dateoffix, m.Latitude, m.Longitude
ORDER BY m.Registration
You can mix Max and Min in the same query.
with firstLast (Registration, firstRec, lastRec) as
(
select [Registration], min([dateOfRecord]) as firstRec, max(dateOfRecord) as lastRec
from GPSPositions
group by [Registration], cast(dateOfRecord as Date)
)
select
fl.Registration as Reg,
Cast(gpsF.dateOfRecord as Date) as [Day],
Cast(gpsF.dateOfRecord as Time) as [StartTime],
gpsF.Latitude as StartLat,
gpsF.Longitude as StartLon,
Cast(gpsL.dateOfRecord as Time) as [EndTime],
gpsL.Latitude as EndLat,
gpsL.Longitude as EndLon
from firstLast fl
inner join GPSPositions gpsF on gpsF.Registration = fl.Registration and gpsF.dateOfRecord = fl.firstRec
inner join GPSPositions gpsL on gpsL.Registration = fl.Registration and gpsL.dateOfRecord = fl.lastRec;
Here is DBFiddle demo.
EDIT: If there could be entries for the same registration at the same time (ID is unique and increasing - ordered by dateOfRecord):
with firstLast (registration,firstRec, lastRec) as
(
select registration,min(id) as firstRec, max(id) as lastRec
from GPSPositions
group by [Registration], cast(dateOfRecord as Date)
)
select
fl.Registration as Reg,
Cast(gpsF.dateOfRecord as Date) as [Day],
Cast(gpsF.dateOfRecord as Time) as [StartTime],
gpsF.Latitude as StartLat,
gpsF.Longitude as StartLon,
Cast(gpsL.dateOfRecord as Time) as [EndTime],
gpsL.Latitude as EndLat,
gpsL.Longitude as EndLon
from firstLast fl
inner join GPSPositions gpsF on gpsF.Id = fl.firstRec
inner join GPSPositions gpsL on gpsL.ID = fl.lastRec;
You could use the APPLY operator and do something like:
DECLARE #t table
(
Registration varchar(10)
, Latitude decimal(6, 3)
, Longitude decimal(6, 3)
, dateOfRecord datetime
)
INSERT INTO #t
VALUES
('A1 XBO', 123.066, 1.456, '2019-08-01 00:04:19.000')
, ('A1 XBO', 128.066, 1.436, '2019-08-01 22:04:19.000')
, ('A1 XBO', 118.066, 1.456, '2019-08-01 23:45:00.000')
SELECT DISTINCT
Registration Reg
, CAST(dateOfRecord AS date) [Day]
, T_MIN.[Time] StartTime
, T_MIN.Latitude StartLat
, T_MIN.Longitude StartLong
, T_MAX.[Time] EndTime
, T_MAX.Latitude EndLat
, T_MAX.Longitude EndLong
FROM
#t T
OUTER APPLY
(
SELECT TOP 1
CAST(T_MIN.dateOfRecord AS time) [Time]
, Latitude
, Longitude
FROM #t T_MIN
WHERE
T_MIN.Registration = T.Registration
AND CAST(T_MIN.dateOfRecord AS date) = CAST(T.dateOfRecord AS date)
ORDER BY T_MIN.dateOfRecord
) T_MIN
OUTER APPLY
(
SELECT TOP 1
CAST(T_MAX.dateOfRecord AS time) [Time]
, Latitude
, Longitude
FROM #t T_MAX
WHERE
T_MAX.Registration = T.Registration
AND CAST(T_MAX.dateOfRecord AS date) = CAST(T.dateOfRecord AS date)
ORDER BY T_MAX.dateOfRecord DESC
) T_MAX
Edit
Based on #SMor's comment, you could also try something like:
DECLARE #t table
(
Registration varchar(10)
, Latitude decimal(6, 3)
, Longitude decimal(6, 3)
, dateOfRecord datetime
)
INSERT INTO #t
VALUES
('A1 XBO', 123.066, 1.456, '2019-08-01 00:04:19.000')
, ('A1 XBO', 128.066, 1.436, '2019-08-01 22:04:19.000')
, ('A1 XBO', 118.066, 1.456, '2019-08-01 23:45:00.000')
SELECT
Reg
, [Day]
, MIN([Time]) StartTime
, MIN(Latitude) StartLat
, MIN(Longitude) StartLong
, MAX([Time]) EndTime
, MAX(Latitude) EndLat
, MAX(Longitude) EndLong
FROM
(
SELECT
Registration Reg
, CAST(dateOfRecord AS date) [Day]
, CAST(dateOfRecord AS time) [Time]
, Latitude
, Longitude
, ROW_NUMBER() OVER (PARTITION BY Registration, CAST(dateOfRecord AS date) ORDER BY dateOfRecord) Mn
, ROW_NUMBER() OVER (PARTITION BY Registration, CAST(dateOfRecord AS date) ORDER BY dateOfRecord DESC) Mx
FROM #t T
) Q
WHERE
Mn = 1
OR Mx = 1
GROUP BY
Reg
, [Day]

Month Aggregation with 0 for NULL results

I have seen something similar but I can't get this to work:
SELECT
CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CALENDAR_MONTH
, CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.TSI_NOMINAL_CODE
, CNTRSINTDATA.DIM_CNTRS_TSI_COA.TSI_NOMINAL_ACC
, CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CNTRS_FIN_YEAR
, SUM (CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.QB_TRANS_AMOUNT) AS CNTRS_ACC_BUDGET
FROM
CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI
, CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY
, CNTRSINTDATA.DIM_CNTRS_TSI_COA
WHERE
CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.QB_TRANS_DATE = CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CALENDAR_DATE
AND CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CNTRS_FIN_YEAR LIKE '2017'
AND CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.TSI_NOMINAL_CODE = CNTRSINTDATA.DIM_CNTRS_TSI_COA.TSI_NOMINAL_CODE
AND CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.TSI_NOMINAL_CODE = '6598'
GROUP BY
CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.TSI_NOMINAL_CODE
, CNTRSINTDATA.DIM_CNTRS_TSI_COA.TSI_NOMINAL_ACC
, CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CALENDAR_MONTH
, CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CNTRS_FIN_YEAR;`
The above query returns results for:
Feb-17 250
Jul-17 400
Jun-17 654
May-17 654
Oct-17 150
Nov-17 250
Aug-17 250
Sep-17
I need the rest of the months to also come back with zero's as there no transactions on the account that month.
Jan-17 0
Feb-17 250
Mar-17 0
Apr-17 0
Jul-17 400
Jun-17 654
May-17 654
Oct-17 150
Nov-17 250
Aug-17 250
Sep-17 0
Dec-17 0
There is a date table that has all the months as VARCHAR2 against date. Just cant get the right syntax. Can anyone help please?
Let's break that down and make it more manageable.
Firstly, translate that to SQL-92 join syntax and add some aliases
SELECT
dcde.CALENDAR_MONTH
, fqtt.TSI_NOMINAL_CODE
, dctc.TSI_NOMINAL_ACC
, dcde.CNTRS_FIN_YEAR
, SUM (fqtt.QB_TRANS_AMOUNT) AS CNTRS_ACC_BUDGET
FROM
CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI fqtt
INNER JOIN CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY dcde
ON fqtt.QB_TRANS_DATE = dcde.CALENDAR_DATE
INNER JOIN CNTRSINTDATA.DIM_CNTRS_TSI_COA dctc
ON AND fqtt.TSI_NOMINAL_CODE = dctc.TSI_NOMINAL_CODE
WHERE
dcde.CNTRS_FIN_YEAR LIKE '2017'
AND
fqtt.TSI_NOMINAL_CODE = '6598'
GROUP BY
fqtt.TSI_NOMINAL_CODE
, dctc.TSI_NOMINAL_ACC
, dcde.CALENDAR_MONTH
, dcde.CNTRS_FIN_YEAR;
Next, you said that there exists a date record (presumably in CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY), so swap that around
SELECT
dcde.CALENDAR_MONTH
, fqtt.TSI_NOMINAL_CODE
, dctc.TSI_NOMINAL_ACC
, dcde.CNTRS_FIN_YEAR
, SUM (fqtt.QB_TRANS_AMOUNT) AS CNTRS_ACC_BUDGET
FROM
CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY dcde
INNER JOIN CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI fqtt
ON fqtt.QB_TRANS_DATE = dcde.CALENDAR_DATE
INNER JOIN CNTRSINTDATA.DIM_CNTRS_TSI_COA dctc
ON AND fqtt.TSI_NOMINAL_CODE = dctc.TSI_NOMINAL_CODE
WHERE
dcde.CNTRS_FIN_YEAR LIKE '2017'
AND
fqtt.TSI_NOMINAL_CODE = '6598'
GROUP BY
fqtt.TSI_NOMINAL_CODE
, dctc.TSI_NOMINAL_ACC
, dcde.CALENDAR_MONTH
, dcde.CNTRS_FIN_YEAR;
Finally, you don't actually want inner joins because that eliminates tuples where there is no match. In this case, you want a left join because you want to have the left value even if no value exists on the right. You also need to coalesce your sum expression to 0 because (for reasons I cannot fathom), the SQL standard defines the sum of a bunch records only containing null as null.
SELECT
dcde.CALENDAR_MONTH
, fqtt.TSI_NOMINAL_CODE
, dctc.TSI_NOMINAL_ACC
, dcde.CNTRS_FIN_YEAR
, COALESCE(SUM (fqtt.QB_TRANS_AMOUNT), 0) AS CNTRS_ACC_BUDGET
FROM
CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY dcde
LEFT JOIN CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI fqtt
ON fqtt.QB_TRANS_DATE = dcde.CALENDAR_DATE
LEFT JOIN CNTRSINTDATA.DIM_CNTRS_TSI_COA dctc
ON AND fqtt.TSI_NOMINAL_CODE = dctc.TSI_NOMINAL_CODE
WHERE
dcde.CNTRS_FIN_YEAR LIKE '2017'
AND
fqtt.TSI_NOMINAL_CODE = '6598'
GROUP BY
fqtt.TSI_NOMINAL_CODE
, dctc.TSI_NOMINAL_ACC
, dcde.CALENDAR_MONTH
, dcde.CNTRS_FIN_YEAR;
Give that a try and see if it is what you want
#Adam G,
Thank you for your suggestion. I actually got an idea from your commentry and instead created a select statement to get all the months I needed first. After that I joined to a select statement picking up the transactions where months matched and it worked. See below (come table names have changed)
SELECT DISTINCT
CNTRS_DATE_ENTITY.CALENDAR_MONTH
, CNTRS_DATE_ENTITY.CNTRS_FIN_MONTH_POS
, COALESCE (TRANS_DATA.TRANS_AMOUNT,0) AS TRANS_AMOUNT
FROM
CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY CNTRS_DATE_ENTITY
LEFT JOIN
(
SELECT
QBS_TRANS_TSI.QB_NOMINAL_CODE
, TO_CHAR(QBS_TRANS_TSI.QB_TRANS_DATE, 'Mon-YY') AS TRANS_MONTH
, COALESCE (SUM(QBS_TRANS_TSI.QB_TRANS_AMOUNT),0) AS TRANS _AMOUNT
FROM
CNTRSINTDATA.FACT_QBS_TRANS_TSI QBS_TRANS_TSI
WHERE
QBS_TRANS_TSI.TSI_NOMINAL_CODE = '6598'
GROUP BY
QBS_TRANS_TSI.QB_NOMINAL_CODE
, TO_CHAR(QBS_TRANS_TSI.QB_TRANS_DATE, 'Mon-YY')
) TRANS_DATA
ON TRANS_DATA.TRANS_MONTH = CNTRS_DATE_ENTITY.CALENDAR_MONTH
WHERE
CNTRS_DATE_ENTITY.CNTRS_FIN_YEAR LIKE '2017'
ORDER BY
CNTRS_DATE_ENTITY.CNTRS_FIN_MONTH_POS
However the results have all the months but have blanks in the entity columns where the sum is zero. Any ideas on a remedy for this?
Here is one possible solution:
Generate fake empty transactions for the target period
for example using CTE:
declare #StartDate datetime = '20170101'
declare #EndDate datetime = '20171231'
;
with dt as
(
select #StartDate As 'thedate'
union all
select dateadd(month, 1, thedate) from dt where thedate < dateadd(month, -1, #EndDate)
)
select
dt.thedate 'row date',
datename(month,dt.thedate) 'Month',
YEAR(dt.thedate) 'Year',
0 'Amount '
from dt
Now you can add them to the transaction table (like union all) or you can do a left join with filtering on the result of your query.
I hope it helps! 🙂

SQL-Server: Return fields where COUNT(*) is greater or equal to 3

I want to get results only for those COUNT that is >= 3
SELECT CustomerNBene.Company, ContractLog.userID
, CONVERT (varchar(10) ,ContractLog.date, 103) as [date]
, CONVERT (varchar(10), ContractLog.LValueDate, 103) as LValueDate
, Payable.ContractNo
, Payable.bank
, Payable.currency
, Payable.Amount
, (
SELECT Count(*)
FROM DimDate
WHERE DimDate.[Date] BETWEEN CONVERT (varchar(10) ,ContractLog.[date], 112)
AND CONVERT (varchar(10), ContractLog.LValueDate, 112) AND DimDate.isweekEND = 0
) as Payable
FROM CustomerNBene, ContractLog, Payable
WHERE ContractLog.contractNo = Payable.ContractNo
AND ContractLog.LConStatus = 'VAL'
AND CustomerNBene.ConNo = ContractLog.contractNo
AND CustomerNBene.CustID != '01'
AND (Payable.Confirmed is NULL or Payable.Confirmed = 'N')
ORDER BY Payable desc, bank
When I add AND Payable >= 3, I get "Invalid Column Name"
How do I go about doing it?
Solution is to use a temptable , insert the result set of your query above in temptable , then apply the filter in temp table.
Try this..
SELECT CustomerNBene.Company, ContractLog.userID
, CONVERT (varchar(10) ,ContractLog.date, 103) as [date]
, CONVERT (varchar(10), ContractLog.LValueDate, 103) as LValueDate
, Payable.ContractNo
, Payable.bank
, Payable.currency
, Payable.Amount
, (
SELECT Count(*)
FROM DimDate
WHERE DimDate.[Date] BETWEEN CONVERT (varchar(10) ,ContractLog.[date], 112)
AND CONVERT (varchar(10), ContractLog.LValueDate, 112) AND DimDate.isweekEND = 0
) as Payable
INTO #TempTable -->> Insert into temp table
FROM CustomerNBene, ContractLog, Payable
WHERE ContractLog.contractNo = Payable.ContractNo
AND ContractLog.LConStatus = 'VAL'
AND CustomerNBene.ConNo = ContractLog.contractNo
AND CustomerNBene.CustID != '01'
AND (Payable.Confirmed is NULL or Payable.Confirmed = 'N')
ORDER BY Payable desc, bank
-->> now apply the filtering in temp table
SELECT Company, userID, date, LValueDate, ContractNo, bank, currency, Amount, Payable
FROM #TempTable
GROUP BY Company, userID, date, LValueDate, ContractNo, bank, currency, Amount, Payable
HAVING COUNT([Payable]) >= 3
you need to know logical order in which statements in queries execute,you can download the poster from the below link and follow numbers to see which operator executes next
http://tsql.solidq.com/books/insidetsql2008/Logical%20Query%20Processing%20Poster.pdf
in simple terms
below query wont work
select name,sum(id) as summ
from test
where summ=10
you can wrap it in a cte.CTE is a disposbale view which is not materialized in DB,but will be valid for scope of single execution
;with cte
as
(
select name,sum(id) as summ
from test
where summ=10
)
select * from cte where summ=10