SSRS Report with date range with group by - sql

I have a table FinalQuote in SQL Server with these columns:
Q_hub_from : Perth, Burnie, Sydney etc.
Q_hub_to : Perth, Burnie, Sydney etc.
FinalMargin : 400, 500, 650 etc.
processed_at : Date Time
BookedYN : Yes/No.
I want to create a SSRS report which will show the average value of FinalMargin for all the rows from a specific Q_hub_from to specific Q_hub_to. Also wanna show average margin in two columns: one contain average of rows where BookedYN is 'YES' and other contain average of rows where BookedYN is 'NO'. It is working fine and display required result when I specify a date range(for processed_at) in query.
My query so far is:
SELECT
Q_hub_from, Q_hub_to,
ROUND(AVG(FinalMargin), 0) AS Margin,
COUNT(*) AS NoOfQuotesDone,
COUNT(CASE BookedYN WHEN 'Yes' THEN 1 ELSE NULL END) AS NoOfQuotesBooked,
ROUND(AVG(CASE BookedYN WHEN 'No' THEN FinalMargin ELSE NULL END), 0) AS MarginWhenNotBooked,
ROUND(AVG(CASE BookedYN WHEN 'Yes' THEN FinalMargin ELSE NULL END), 0) AS MarginWhenBooked
FROM
FinalQuote
WHERE
Q_hub_from <> ''
AND Q_hub_from IS NOT NULL
--AND CAST(processed_at as date) BETWEEN '2018-08-01' AND '2018-10-10'
AND CAST(processed_at AS DATE) BETWEEN DATEADD(day, -10, GETDATE()) AND GETDATE()
GROUP BY
Q_hub_from, Q_hub_to
ORDER BY
Q_hub_from ASC
This query produces this output:
But I want date range to be selected by user, so I added StartDate and EndDate parameters. My processed_at column only mentioned in the WHERE clause, not in the select statement, so I get this error:
[rsMissingFieldInDataSet] and [rsErrorReadingDataSetField]
When I add processed_at field in DataSet and in GROUP BY clause then it is working (although still displays previous error) but now result is not expected. It shows 2 rows for same Q_hub_from and Q_hub_to.
Query:
SELECT Q_hub_from, Q_hub_to, processed_at, ROUND(AVG(FinalMargin),0) AS Margin,
COUNT(*) AS NoOfQuotesDone, COUNT(case BookedYN when 'Yes' then 1 else null end) AS NoOfQuotesBooked,
ROUND(AVG(case BookedYN when 'No' then FinalMargin else null end),0) AS MarginWhenNotBooked, ROUND(AVG(case BookedYN when 'Yes' then FinalMargin else null end),0) AS MarginWhenBooked
FROM FinalQuote
WHERE Q_hub_from <> '' AND Q_hub_from IS NOT NULL
AND processed_at between #StartDate AND #EndDate
GROUP BY Q_hub_from, Q_hub_to, processed_at
ORDER BY Q_hub_from ASC
Output:
If anyone can help me in achieving the required result that only show 1 row for same Q_hub_from to Q-hub_to within specific date range(i.e. processed_at between StartDate and EndDate) that will be of great help. I don't wanna display processed_at column. I know I am doing something wrong as Its my first time with SSRS.
Feel free to ask if you want to know more. Any help will be appreciated! Thanks.

If you have not set the values for parametes then try to assign some values to parameters and make sure parameter type is Date.
You can do it like this,
create a dataset and put this query select DATEADD(day, -10, GETDATE()) AS StartDate, GETDATE() AS EndDate
Use this dataset for your both the parameters only in default values section. Don't add it in available values section.

Suggestion 1: AND cast( processed_at as date) between #StartDate AND #EndDate . As you need to make sure how this column is stored in the tables. If it is DateTime then do an implicit cast to date.
Suggestion 2: on the SSRS make sure you can see your 2 params are params. IF you do then DO NOT SET any values for them. See if you can pick any random range and report renders.
Suggestion 3: if you have to put default values make sure they are either query or best case stored proc generated (sometime like usp_report_params_defaultDateRange). You will give this for default date range. Also type will be date and not int, varchar, etc.
Suggestion 4: If above fail trying building a query and just hardcoding the values so something like Select '2000-01-01' as Q_hub_from, '2001-01-01' as Q_hub_to from table name where cast( processed_at as date) between #StartDate AND #EndDate and see if it works. Add 1 column at a time and anchor to report and see if it gives you error. (NOTE YOU HAVE TO DELETE .DATA file from your local Bin folder after each local successful run)

Related

MIN and MAX in case expression

I want to get MIN or Max date base on condition(s.REQUIRED_DATE >= trunc(SYSDATE-1)).
Below is my query.
It gives me error ORA-00937: not a single-group group function
SELECT
case when s.REQUIRED_DATE >= trunc(SYSDATE-1) then
MIN(required_date)
else
MAX(required_date)
end required_date
FROM anytable s
WHERE s.abc = 'hhj';
How can I achieve this?
Query must return 17-AUG-2020 for 'hhj' and 15-AUG-2020 for 'bbj'
id abc required_date
1 hhj 14-Aug-2020
2 hhj 17-AUG-2020
3 hhj 19-AUG-2020
3 bbj 15-AUG-2020
4 bbj 12-AUG-2020
I can adopt any other approach also if required.
Please suggest
It seems, for a particular abc you want to get:
the required_date nearest to and past the date yesterday if there's a required_date past the date yesterday, or
get the latest required_date if they don't pass the date yesterday.
If so, this query may be what you wanted:
select
case when max(required_date)>=trunc(sysdate-1) then
min(case when required_date>=trunc(sysdate-1) then required_date end)
else max(required_date)
end required_date
from anytable s
where s.abc='hhj';
Use Aggregate function on whole case statement and for this you have to use two case statements.
SELECT
MIN(case when s.ENTRY_DATE >= trunc(SYSDATE-1) then
ENTRY_DATE
end) MIN_required_date,
MAX(case when s.ENTRY_DATE < trunc(SYSDATE-1) then
ENTRY_DATE
end) MAX_required_date
FROM DATE_TEST s

aggregate function error in case expression

I have this query
SELECT mylearning.Employee_Id,
case
when max(case when not mylearning.CourseStatusTXT = 'Completed' then 1 else 0 end) = 0 then '2018 Complete'
when max(case when mylearning.CourseStatusTXT in ('Started', 'Not Started') then 1 else 0 end) = 1 then '2018 Not Complete'
end as Completion_Status
FROM Analytics.myLearning_Completions as mylearning inner join Analytics.Workday WD on mylearning.Employee_ID = WD.Employee_ID
And I want to add a condition to the first when statement to make it like this
when max(case when not mylearning.CourseStatusTXT = 'Completed' then 1 else 0 end) = 0
and WD.Adjusted_Hire_Date like '2019% '
and mylearning.CourseTimeCompletedH < cast (WD.Adjusted_Hire_Date as date format 'YYYY/MM/DD') +7
then '2018 Complete'
but I keep getting this error
Executed as Single statement. Failed [3504 : HY000] Selected non-aggregate values must be part of the associated group.
Elapsed time = 00:00:00.069
How can I fix it?
Like a couple others mentioned, you are trying to mix grouped data with non-aggregated data in your calculation, which is why you're getting the 3504 error. You need to either include the referenced columns in your GROUP BY or include them inside an aggregate function (i.e. MAX).
I'm not 100% sure if this is what you're after, but hopefully it can help you along.
SELECT
mylearning.Employee_Id,
CASE
WHEN
MAX(CASE WHEN NOT mylearning.CourseStatusTXT = 'Completed' THEN 1 ELSE 0 END) = 0 AND
WD.Adjusted_Hire_Date like '2019% ' AND
-- Check if most recently completed course is before Hire (Date + 1 week)
MAX(mylearning.CourseTimeCompletedH) <
CAST(WD.Adjusted_Hire_Date AS DATE FORMAT 'YYYY/MM/DD') + 7
THEN '2018 Complete' -- No incomplete learnings
WHEN MAX(
CASE WHEN mylearning.CourseStatusTXT IN ('Started', 'Not Started') THEN 1 ELSE 0 END
) = 1 THEN '2018 Not Complete' -- Started / Not Started learnings exist
END AS Completion_Status
FROM Analytics.myLearning_Completions as mylearning -- Get learning info
INNER JOIN Analytics.Workday WD on mylearning.Employee_ID = WD.Employee_ID -- Employee info
GROUP BY mylearning.Employee_Id, WD.Adjusted_Hire_Date
This will give you a summary per employee, with a couple assumptions:
Assuming employee_ID value in Analytics.Workday is a unique value (one-to-one join), to use WD.Adjusted_Hire_Date in your comparisons, you just need to include it in the GROUP BY.
Assuming you have multiple courses per employee_Id, in order to use mylearning.CourseTimeCompletedH in your comparisons, you'd need to wrap that in an aggregate like MAX.
The caveat here is that the query will check if the most recently completed course per employee is before the "hire_date" expression, so I'm not sure if that's what you're after.
Give it a try and let me know.
The issue here is that you are mixing detail row by row information in the same query as group or aggregated data. Aggregated data will output a single value for all the rows unless you have a group by clause. If you have a group by clause then it will output a single value for each group. When you are grouping you can also include any values that are in the group by clause since they will be unique for the group.
if you want this data for each employee, then you could group by employee_id. Any other data would need to also be an aggregate like Max(Adjusted_Hire_Date)
Maybe this is what you want?
SELECT
mylearning.employee_id
, case
when CourseStatusTXT = 'Completed' and WD.Adjusted_Hire_Date like '2019%'
and mylearning.CourseTimeCompletedH < cast (WD.Adjusted_Hire_Date as date format 'YYYY/MM/DD') +7
then '2018 Complete'
else '2018 Not Complete'
end CompletionStatus
FROM myLearning_Completions mylearning, Workday WD
WHERE mylearning.employee_id = WD.employee_id

Conversion failed when converting the varchar value 'RESOLVED SATURDAY' to data type int

Good Afternoon,
I'm having a few issues with trying to add text into a existing table, i'm trying to add the text 'resolved saturday' or 'resolved sunday' with the below code:
Insert Into tblwb_tt_RFID_DO (ItemID, ReceiverID, DMFsenderpanellisttypeid,
DMFReceiverPanellistTypeID, ClassofMailID, DMFCalendarDateofPosting,
QualityofServiceDateofPosting, DateofReceipt, FirstReadDate, FirstReadTime,
FirstReadSite, Lastreadday, Lastreaddate, Lastreadtime, LastReadSite,
ReceivesOnSaturday, ReceiverPostcode, freq, DMFanalysisperiodid,
EmailAddress, [Action])
select d.ItemID,
d.ReceiverId,
d.DMFsenderPanellistTypeID,
d.DMFReceiverPanellistTypeID,
d.ClassOfMailID,
CAST (d.DMFCalendarDateOfPosting as date) as 'DMFCalendarDateofposting',
CAST (d.QualityOfServiceDateOfPosting as date) as
'Qualityofservicedateofposting',
CAST (d.DateOfReceipt as date) as 'Dateofreceipt',
CAST (d.FirstReadDate as date) as 'FirstReadDate',
CAST (d.FirstReadDate as time) as 'FirstReadTime',
d.FirstReadSite,
datename (dw, d.lastreaddate) as 'LastReadDay',
CAST (d.LastReadDate as date) as 'Lastreaddate',
CAST (d.LastReadDate as time) as 'Lastreadtime',
d.LastReadSite,
CASE WHEN d.DMFReceiverPanellistTypeId = 2 then 1
ELSE d.ReceivesOnSaturday
END as 'ReceivesOnSaturday',
a.PostCode as 'Receiver Postcode',
CASE WHEN ReceiverId is not null then 1
END as 'freq',
CASE WHEN Datename (dw, d.lastreaddate) = 'Saturday' AND DATEDIFF(dd,DateOfReceipt,LastReadDate) <=2 THEN 'RESOLVED SATURDAY'
ELSE CASE WHEN Datename (dw, d.lastreaddate) = 'Sunday' AND DATEDIFF(dd,DateOfReceipt,LastReadDate) <=1 THEN 'RESOLVED SUNDAY'
ELSE NULL END
END AS 'Action',
d.DMFanalysisperiodid,
p.EmailAddress
from rmlivecopy..tblrmrsnapshot d
join rmlivecopy..tblPanellist p
on p.PanellistId = D.ReceiverId
join rmlivecopy..tblAddress A
on A.panellistID = P.panellistID
join rmlivecopy..tblItemPlanInfo c
on c.ItemId = d.ItemId AND d.dmfstatusID = 6
left join rmlivecopy..tblitemquery iq on d.itemid = iq.itemid
where d.DMFSurveysId in (1, 2, 5)
and iq.querycode = 'R1'
and iq.queryuseractionid = 'C'
and iq.queryuseractionid <> 'A'
and d.firstreadsite is not NULL
and d.lastreadsite is not NULL
and LastReadSite LIKE '%B1%'
and DATEDIFF(dd,DateOfReceipt,LastReadDate) != 0
and datepart(hh,LastReadDate) > 6
and datepart(hh,LastReadDate) < 18
and d.DMFanalysisperiodid like ('18%')
Now when I try to just select the data, the code works fine, shows me exactly what I want with the records that fall under these conditions being flagged as such in the Action column, but when I try to Insert into the table, I get the error 'Conversion failed when converting the varchar value 'RESOLVED SATURDAY' to data type int.'
I understand I might be having a issue with the case trying to just use the data type int format, but for the life of me I can't think on how to resolve it. Any ideas? I know I should be able to use convert somewhere but I can't think where...
EDIT - Added the Full Insert Statement
The Action Column i'm trying to insert into is Nvarchar(50)
EDIT 2 - I've managed to resolve it, I managed to get the insert statement the wrong way round, adjusted and now working as expected. Thank you guys for the help :)
Hmmm. There is nothing obvious in your code that would cause this problem, unless the "date" columns contain weird strings (which I doubt).
One typical cause of this problem is when the different values returned by a case expression are of different types. If one is a number, then all are converted to numbers.
I would suggest that you simplify the case expression. There is no need to nest them. This may help fix the error:
(CASE WHEN Datename(dw, d.lastreaddate) = 'Saturday' AND DATEDIFF(day, DateOfReceipt, LastReadDate) <= 2
THEN 'RESOLVED SATURDAY'
WHEN Datename(dw, d.lastreaddate) = 'Sunday' AND DATEDIFF(day, DateOfReceipt, LastReadDate) <= 1
THEN 'RESOLVED SUNDAY'
END) AS Action,

Getting derived column from database | SQL query | DB2 SystemDate

My table is PRODUCTINFO:
Column name : product_name | launch_date
Sample Date : product1 2017-01-20
I need a SQL query to decide if the product is newly launched or not.
Business rule :
if (launch_date - currentdate < 0 && currentdate - launch_date < 90)
newly_launched = 'YES'
else
newly_launched = 'NO'
where currentdate is today's date.
SQL query I am witting is like :
SELECT launch_date, X as newly_launched
FROM PRODUCTINFO
WHERE product_name = 'product1'
I am not able to figure out correct replacement of 'X' in my query for desired result.
Problem I am facing is using currentdate and if else block in my query
Please help.
One way to get currentdate in DB2 using following query :
SELECT VARCHAR_FORMAT(CURRENT TIMESTAMP, 'YYYYMMDD')
FROM SYSIBM.SYSDUMMY1
Still not sure how to use this with my if else scenario.
Answer here don't solve my problem as this scenario is if-else based.
use TIMESTAMPDIFF with 16 as first parameter for count number days between 2 timestamps, for more detail look here
try this
select launch_date,
case when TIMESTAMPDIFF( 16, cast(cast(launch_date as timestamp) - current timestamp as char(22))) >0 and
TIMESTAMPDIFF( 16, cast(cast(launch_date as timestamp) - current timestamp as char(22))) <90 then 'YES' else 'NO' end newly
from PRODUCTINFO
WHERE product_name = 'product1'
simply use datediff function in a case syntax, I hope it could help!
SELECT launch_date,
case
when DATEDIFF(day,launch_date,getdate()) BETWEEN 0 AND 90 then 'YES'
else 'NO'
end AS newly_launched
FROM PRODUCTINFO
WHERE product_name = 'product1'
in case you want to do it for all your records:
SELECT launch_date,
case
when DATEDIFF(day,launch_date,getdate()) BETWEEN 0 AND 90 then 'YES'
else 'NO'
end AS newly_launched
FROM PRODUCTINFO

Stored procedure to suppress default values of '1900-01-01 00:00:00.000'

So I'm working on a system that uses default date values of '1900-01-01 00:00:00.000' rather than allowing nulls. I've got a stored procedure that displays all members of an association and the date and amounts charged to them. If a member has not received charges, I need to display a zero amount and empty string for the date. I've tried every permutation of CASE and CONVERT I can think of, but I can't seem to suppress the default date. It's the column trandate I'm trying to manipulate. Any pointers are greatly appreciated! Here is my current code, and below that the current results.
ALTER PROCEDURE [dbo].[usp_ApplyCharges_GetAllAssociationsDebtors]
#tCode int,
#AssnKey int
WITH RECOMPILE
AS
SELECT
c.pkey,
c.lname + ', ' + c.fname as 'Name',
c.address1,
c.address2,
c.assnkey,
cs.camount as 'LastAmt',
coalesce(c.AssmtChrgAmt, 0) as 'DefaultAmt',
cs.trancode,
a.name as 'AssnName' ,
a.assmtchrgamt,
a.latefee,
CASE
WHEN cs.trandate = '1900-01-01 00:00:00.000' THEN ''
ELSE cs.trandate
END AS lasttrandate,
CASE a.assmtchrgfreq
WHEN 'A' THEN 'Annual'
WHEN 'D' THEN 'Daily'
WHEN 'B' THEN 'Bi-Monthly'
WHEN 'M' THEN 'Monthly'
WHEN 'Q' THEN 'Quarterly'
WHEN 'S' THEN 'Semi-Annual'
WHEN 'T' THEN 'Tri-Annual'
ELSE 'N/A'
END
AS AssessmentFrequency
FROM
Cases c LEFT OUTER JOIN CaseSumm cs
ON c.pkey = cs.casekey
INNER JOIN vw_CaseSumm_GetLastpKeyByTrantype v
ON cs.pkey = v.pkey
INNER JOIN assnctrl a
ON c.assnkey = a.pkey
WHERE
v.trancode = #tcode and v.assnkey = #assnkey and c.active = 1
UNION
SELECT c2.pkey,
c2.lname + ', ' + c2.fname as 'Name',
c2.address1,
c2.address2,
c2.assnkey,
0,
0,
0,
a.name as 'AssnName',
a.assmtchrgamt,
a.latefee,
'',
CASE a.assmtchrgfreq
WHEN 'A' THEN 'Annual'
WHEN 'D' THEN 'Daily'
WHEN 'B' THEN 'Bi-Monthly'
WHEN 'M' THEN 'Monthly'
WHEN 'Q' THEN 'Quarterly'
WHEN 'S' THEN 'Semi-Annual'
WHEN 'T' THEN 'Tri-Annual'
ELSE 'N/A'
END
As AssessmentFrequency
FROM
Cases c2 INNER JOIN AssnCtrl a
ON c2.assnkey = a.pkey
WHERE c2.assnkey = #assnkey and c2.active = 1
and c2.pkey NOT IN
(SELECT casekey FROM vw_CaseSumm_GetLastpKeyByTrantype WHERE assnkey = #assnkey and trancode = #tcode)
ORDER BY Name
Result example:
142373 Smith, John 1234 Main St. 84 0.00 0 0 Ashley Place Condominium, Inc. 333.00 0 1900-01-01 00:00:00.000 Tri-Annual
The problem is that all possible values of a CASE statement must have the same DataType, and the most restrictive possibility will be used.
You are trying to return an empty string in one case, but in the other case you return a DateTime type. That means that the empty string will be implicitly converted to a DateTime, which will default to 1900-01-01.
If you CAST the datetime value to a string, then both sides will return a string and you will be able to return an empty string. Like so:
CASE
WHEN cs.trandate = '1900-01-01 00:00:00.000' THEN ''
ELSE CONVERT(varchar(31),cs.trandate)
END AS lasttrandate,
Of course this is only a useful answer if you can accept a having a string for an output datatype for that column. If you need the datatype to be a date-time, then you will have to accept the 1900-01-01 output and handle it in your front end.
Change this:
WHEN cs.trandate = '1900-01-01 00:00:00.000' THEN ''
into this
WHEN CAST(cs.trandate AS DATE) = '19000101' THEN NULL
Comparing date-times is always fraught with error for the same reason comparing floats is. This just pulls the actual date part and does the comparison, which is good enough I think for your case.
Also, since the column type is 'datetime', the THEN '' will be cast to a date time, which will end up being "mindate"... or 1900-01-01. You really want NULL here, and to adjust the rest of the query as necessary to deal with NULLs.
Wow, thanks guys! SO many great responses so quickly. I tried them all, and in the end the suggestion from Tab Alleman hit the home run for me. I did make a slight modification to
ELSE CONVERT(varchar(10),cs.trandate, 101) so that I can a short date in return. Aside from that, this is exactly what I was looking for, and it makes perfect sense the way you explained it, Tab.
Thanks again to all who helped!