Select a row with the highest column value - reporting-services

How would I code a filter on an SSRS tablix to select only the highest value (of an ID number) when another value is duplicated?
EmpID RecordID Status
100 10001 OUT
101 10002 IN
102 10003 IN
102 10004 OUT
103 10005 IN
I have a report that creates a dataset that may contain duplicate employee IDs. If the Employee ID is the same I want the SSRS Tablix to ONLY select the one with the Higher Record ID. The report is already written and the easiest way for me to fix this is to just add a filter to the Tablix rather than mess with the query.
If the query is easier to amend Im fine with that as well. Here is the existing code. If the EMPID appears more than once for any given employee...then only use the data row with the HID with the greater value.
What is happening is this is a web form that shows employee status for the day. If an employee submits a change or updates their schedule it actually creates a new row in the table for the week. The submission form is flawed but thats an issue for another day. I just need it to only read the last edit. HID is the incrementing value each time a new row is added.
SELECT Absences.Type, humres.fullname, humres.res_id, Absences.StartDate, DATEADD(dd, - (DATEPART(dw, Absences.StartDate) - 2), Absences.StartDate) AS FirstDayOfWeek, Absences.FreeTextField_01 AS Monday,
Absences.FreeTextField_02 AS Tuesday, Absences.FreeTextField_03 AS Wednesday, Absences.FreeTextField_04 AS Thursday, Absences.FreeTextField_05 AS Friday, Absences.HID,
CASE WHEN Absences.FreeTextField_01 <> 'Office' AND DATENAME(weekday, GETDATE()) = 'Monday' THEN Absences.FreeTextField_01 WHEN Absences.FreeTextField_02 <> 'Office' AND DATENAME(weekday, GETDATE())
= 'Tuesday' THEN Absences.FreeTextField_02 WHEN Absences.FreeTextField_03 <> 'Office' AND DATENAME(weekday, GETDATE())
= 'Wednesday' THEN Absences.FreeTextField_03 WHEN Absences.FreeTextField_04 <> 'Office' AND DATENAME(weekday, GETDATE())
= 'Thursday' THEN Absences.FreeTextField_04 WHEN Absences.FreeTextField_05 <> 'Office' AND DATENAME(weekday, GETDATE()) = 'Friday' THEN Absences.FreeTextField_05 ELSE '' END AS Status
FROM humres LEFT OUTER JOIN
Absences ON humres.res_id = Absences.EmpID
WHERE (humres.emp_stat = 'A') AND (humres.freefield16 = 0) AND (Absences.StartDate BETWEEN DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0) AND DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 4)) AND (NOT (humres.res_id IN (1, 248)))
AND (humres.emp_type = 'E') AND (humres.blocked = 0) AND (Absences.Type = 161) AND (CASE WHEN Absences.FreeTextField_01 <> 'Office' AND DATENAME(weekday, GETDATE())
= 'Monday' THEN Absences.FreeTextField_01 WHEN Absences.FreeTextField_02 <> 'Office' AND DATENAME(weekday, GETDATE())
= 'Tuesday' THEN Absences.FreeTextField_02 WHEN Absences.FreeTextField_03 <> 'Office' AND DATENAME(weekday, GETDATE())
= 'Wednesday' THEN Absences.FreeTextField_03 WHEN Absences.FreeTextField_04 <> 'Office' AND DATENAME(weekday, GETDATE())
= 'Thursday' THEN Absences.FreeTextField_04 WHEN Absences.FreeTextField_05 <> 'Office' AND DATENAME(weekday, GETDATE()) = 'Friday' THEN Absences.FreeTextField_05 ELSE '' END <> '')
ORDER BY FirstDayOfWeek, Absences.HID DESC

It will be much more work doing it in SSRS.
To do this in SSRS you would have to group by EmpID and then get MAX(RecordID), then you would have to do a LOOKUP back to the same dataset using a combined key of EmpID and MAX(RecordID) to get the Status that matches the last one. Messy and hard to debug.
In SQL it's a pretty trivial task. If the current query is complex then you can always get the result of this and then process it further, all within the dataset query.
So, if a simple version of your current query looks like this...
SELECT
EmpID, RecordID, Status
FROM myTable
You can just dump the results into a temp table and then process further
SELECT
EmpID, RecordID, Status
INTO #t
FROM myTable
SELECT EmpID, RecordID, Status
FROM (
SELECT *, ROW_NUMBER() OVER(PARTITION BY EmpID ORDER BY RecordID DESC) as RowN FROM #t
) r
WHERE r.RowN = 1
This will give you the desired results

Related

Need to align as one row SQL

I have some data which I am trying to align as one row instead of two.
Example what I am getting
Name Feb Mar
Tom $229.32 NULL
Tom NULL $182.63
How I need is below
Name Feb Mar
Tom $229.32 $182.63
Below is the query which I am using
select Name,
case
when convert(varchar(7), bill_dt, 126) = '2018-02'
then sum(cast(amount as float))
end Feb,
case
when convert(varchar(7), bill_dt, 126) = '2018-03'
then sum(cast(amount as float))
end Mar
from psi.eop_stagging
where bill_dt >= '2018/02/01' and bill_dt < '2018/04/01'
group by Name, bill_dt
Use conditional aggregation:
select Name,
SUM( case when convert(varchar(7), bill_dt, 126) = '2018-02'
then cast(amount as float)
else 0
end) as Feb,
SUM( case when convert(varchar(7), bill_dt, 126) = '2018-03'
then cast(amount as float)
else 0
end) as Mar
from psi.eop_stagging
where bill_dt >= '2018/02/01' and bill_dt < '2018/04/01'
group by Name
For your dataset, use a query that "reduces" the billing date to the first of the month (to give the report something to group by), for example:
select
Name,
DATEADD(month, DATEDIFF(month, 0, bill_dt), 0) AS bill_mnth,
amount
from psi.eop_stagging
where bill_dt >= '2018/02/01' and bill_dt < '2018/04/01';
You do not have to group yet, you can let the report do this for you. And don't use anything that sounds sophisticated and starts with "conditional", unless you want to use your report only for Febuary and March 2018.
Add a matrix to the report and use the field selector to select
Name for Rows
bill_mnth for Columns and
amount for Data
This will create a Row group grouped by Name and a Column group grouped by bill_mnth. In order to display the 3-letter abbreviation of the month instead of a date, right-click the TextBox and change the expression of that column header to
=Format(Fields!bill_mnth.Value, "MMM")
... or even "MMM yyyy" if you plan to enlarge the interval. And of course, format the data cell as desired.

how to group by week start from friday

I have table sql like this:
This my query for count tgl:
SELECT count( tgl ) AS total, absen.id
FROM absen
WHERE absen.status = 'm'
GROUP BY absen.id
So I want group by absen.id and absen.tgl
How to group by week from Friday to Thursday?
2016-01-08 is friday and 2016-01-15 is thursday.
Bellow query can bring the result you want, but i think you defined the wrong end date, because in your example from 2015-01-08 up to 2015-01-15 its 8 day and one week has 7 days.
select
count( tgl ) AS total,
absen.id,
CASE WHEN (weekday(tgl)<=3) THEN date(tgl + INTERVAL (3-weekday(tgl)) DAY)
ELSE date(tgl + INTERVAL (3+7-weekday(tgl)) DAY)
END as week_days
FROM absen
WHERE status = 'm'
GROUP BY id,week_days
here is the fiddle fiddle
Query Description:
mysql weekday array numbers:
$weekArr = array(
'Monday' => 0,
'Tuesday' => 1,
'Wednesday' => 2,
'Thursday' => 3,
'Friday' => 4,
'Saturday' => 5,
'Sunday' => 6);
So now suppose today is Tuesday and date is 2016-01-12, now let's count from today towards the start date in our table which is 2016-01-07 and it match with Thursday of past week, so according to the weekday array number its weekday(2016-01-07) == 3 so it goes to the WHEN part of our query, and query will select something like this CASE WHEN (weekday('2016-01-07') <= 3) THEN date('2016-01-07' + INTERVAL(3-3)) that is equal to SELECT '2016-01-07' and so on for others.
I just found how to get this by trouble shooting on excel by using this WEEK('date' + INTERVAL 3 DAY, 3)

Sales and transaction totals by part, grouped by last 24 months

SELECT det.partNum,
SUM(det.quantity) AS Demand1,
COUNT(det.partNum) AS Call1
FROM details det
JOIN invoice inv ON det.invoice_id = inv.id
WHERE inv.invoice_date
BETWEEN '2015-11-01 00:00:00'
AND '2015-11-31 23:59:59'
GROUP BY partNum
The above sql returns all part numbers, the total number sold (Demand), and the total number of transactions the parts were involved in (Call) for the current month.
What our vendor wants is this information for every part, but also grouped for each of the past 24 months. The csv they are requesting would look like the following (if only viewing the last 3 months):
Part# | Demand1 | Demand2 | Demand3 | Call1 | Call2 | Call3
123 | 0 | 2 | 0 | 0 | 1 | 0
345 | 6 | 3 | 4 | 1 | 2 | 3
Part# 123: 0 transactions this month (Call1) 0 quantity sold (Demand1)
1 transaction last month (Call2) 2 quantity sold (Demand2).
0 transactions two months ago (Call3) 0 quantity sold (Demand3).
Part# 345: 1 transaction this month (Call1) for qty sold of 6 (Demand1)
2 transactions last month (Call2) for qty sold of 3 (Demand2)
3 transactions two months ago (Call3) for qty sold of 4 (Demand3)
Realize that they want this extended out for the past 24 months. Demand1/Call1 are always the current month.
I used the WHERE/BETWEEN statement to show where the date is coming from and to demonstrate how I can get an accurate report of the parts for the current month.
What I can't figure out how to do is to fill Demand and Call for 24 months. And this is the format that the vendor expects the data to be in. This wasn't my choice. Any help in getting this working as expected would be greatly appreciated.
Thanks
EDIT
I removed the sql-server tag. Sorry about that. This is only MySQL.
Also, I'm adding my reply from below...
Looking into DATEDIFF, TIMESTAMPDIFF, and even PERIOD_DIFF. But none actually seem to return what I need. What needs to happen is the first demand column should search for the current month, day 1 (inclusive) through the next month, day 1 (exclusive). The next demand column should search the current month - one month, day 1 (inclusive) through next month - one month, day 1 (exclusive). And each subsequent column should search the same parameters, subtracting an additional month each column. I don't think that can be accomplished with precision simply using DATEDIFF.
I hope that makes sense.
And again, thanks for any help.
If I understood your problem correctly, you can do it like this:
SELECT
det.partNum,
SUM(case when inv.invoice_date >= dateadd(month, -3, #currMonth) and inv.invoice_date < dateadd(month, -2, #currMonth) then det.quantity else 0) AS Demand1,
SUM(case when inv.invoice_date >= dateadd(month, -2, #currMonth) and inv.invoice_date < dateadd(month, -1, #currMonth) then det.quantity else 0) AS Demand2,
...
FROM details det
JOIN invoice inv ON det.invoice_id = inv.id
WHERE
inv.invoice_date >= '2015-11-01 00:00:00' AND inv.invoice_date < '2015-12-01'
GROUP BY partNum
This uses a variable that has the start date of current month to make the SQL more simple. I also changed the where clause, you should really use >= + < with dates instead of between.
This might get you started with Pivot query.
;WITH cte AS
(
SELECT det.partNum,
SUM(det.quantity) AS DemandSum,
COUNT(det.partNum) AS CallCount,
DATEDIFF(MONTH,inv.invoice_date, GETDATE()) + 1 MonthDiff
FROM details det
JOIN invoice inv ON det.invoice_id = inv.id
GROUP BY det.partNum, DATEDIFF(MONTH,inv.invoice_date, GETDATE()) + 1
)
SELECT t.partNum,
[Demand1],[Demand2],[Demand3],[Demand4],[Demand5],[Demand6],[Demand7],[Demand8],[Demand9],[Demand10],[Demand11],[Demand12],
[Demand13],[Demand14],[Demand15],[Demand16],[Demand17],[Demand18],[Demand19],[Demand20],[Demand21],[Demand22],[Demand23],[Demand24],
[Call1],[Call2],[Call3],[Call4],[Call5],[Call6],[Call7],[Call8],[Call9],[Call10],[Call11],[Call12],
[Call13],[Call14],[Call15],[Call16],[Call17],[Call18],[Call19],[Call20],[Call21],[Call22],[Call23],[Call24]
FROM (SELECT DISTINCT partNum FROM cte) t
LEFT JOIN (
SELECT * FROM (
SELECT partNum, DemandSum, CONCAT('Demand',MonthDiff) ColName FROM cte
) c PIVOT (SUM(DemandSum) FOR ColName IN ([Demand1],[Demand2],[Demand3],[Demand4],[Demand5],[Demand6],[Demand7],[Demand8],[Demand9],[Demand10],[Demand11],[Demand12],
[Demand13],[Demand14],[Demand15],[Demand16],[Demand17],[Demand18],[Demand19],[Demand20],[Demand21],[Demand22],[Demand23],[Demand24])
) p
) ds ON ds.partNum = t.partNum
LEFT JOIN (
SELECT * FROM (
SELECT partNum, CallCount, CONCAT('Call',MonthDiff) ColName FROM cte
) c PIVOT (COUNT(CallCount) FOR ColName IN ([Call1],[Call2],[Call3],[Call4],[Call5],[Call6],[Call7],[Call8],[Call9],[Call10],[Call11],[Call12],
[Call13],[Call14],[Call15],[Call16],[Call17],[Call18],[Call19],[Call20],[Call21],[Call22],[Call23],[Call24])
) p
) cc ON cc.partNum = t.partNum
if that's too confusing, you can use the CASE method. I'd do it a little different than the other answer though..
SELECT
det.partNum,
SUM(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 0 then det.quantity else 0 end) AS Demand1,
SUM(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 1 then det.quantity else 0 end) AS Demand2,
SUM(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 2 then det.quantity else 0 end) AS Demand3,
COUNT(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 0 then det.partNum end) AS Call1,
COUNT(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 1 then det.partNum end) AS Call2,
COUNT(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 2 then det.partNum end) AS Call3
FROM
details det
JOIN invoice inv ON det.invoice_id = inv.id
GROUP BY
det.partNum
you can get the full script for all 24 months here.. SQL Fiddle

Get records between two time values in MS Acess

I have a datetime field. I want to get the records between 9AM and 5PM also I need the records between 5PM AND 9AM. If I am using between operator it gives me the same number of records.
SELECT count(*)
FROM DirectLineMainCallQuery AS CallTbl
Where Format(CallTbl.CallDate,"dddd") <> 'Saturday' AND Format(CallTbl.CallDate,"dddd") <> 'Sunday'
AND (Format(CallTbl.StartTime,'hh:mm') Between '09:00' AND '17:00')
UNION ALL
SELECT count(*)
FROM DirectLineMainCallQuery AS CallTbl
Where Format(CallTbl.CallDate,"dddd") <> 'Saturday' AND Format(CallTbl.CallDate,"dddd") <> 'Sunday'
AND (Format(CallTbl.StartTime,'hh:mm') Between '17:00' AND '09:00') ;
Any help would be appreciated.
Thanks
AK47 has the correct comment, of needing two time ranges, the second one being either 1700 to midnight, or 0000 to 0900, as below-- Notice the extra pair of parens that enclose the last two betweens...
SELECT Count(*)
FROM directlinemaincallquery AS CallTbl
WHERE Format(CallTbl.calldate, "dddd") <> 'Saturday'
AND Format(CallTbl.calldate, "dddd") <> 'Sunday'
AND ( Format(CallTbl.starttime, 'hh:mm') BETWEEN '09:00' AND '17:00' )
UNION ALL
SELECT Count(*)
FROM directlinemaincallquery AS CallTbl
WHERE Format(CallTbl.calldate, "dddd") <> 'Saturday'
AND Format(CallTbl.calldate, "dddd") <> 'Sunday'
AND (( Format(CallTbl.starttime, 'hh:mm') BETWEEN '17:00' AND '23:59' )
OR ( Format(CallTbl.starttime, 'hh:mm') BETWEEN '00:00' AND '09:00' ));
Edited 4/6 nite
You said -- If I am using between operator it gives me the same number of records
And MSACCESS agrees with you... Between 9 and 17 is the same as Between 17 and 9
I created this test, and got this result----
SELECT table1.*
FROM table1
Where Frame between '8' and '3'
Frame
3
4
5
6
7
8
MSACCESS does not care that the "larger" is before the "smaller", but rather gives you BETWEEN the smaller and the larger of the two values. While you may think that it should "Do What I Mean", it cannot. The way to ask it is to make two Betweens for 17--thru--2359 and 0000 thru 0900 as shown in my example, or to use Greater/Lessor signs (>= <= ).
Please try following code,
SELECT count(*)
FROM DirectLineMainCallQuery AS CallTbl
Where Format(CallTbl.CallDate,"dddd") <> 'Saturday' AND Format(CallTbl.CallDate,"dddd") <> 'Sunday'
AND (Format(CallTbl.StartTime,'hh:mm') >= '09:00' AND (CallTbl.StartTime,'hh:mm') < '17:00')
Union All
SELECT count(*)
FROM DirectLineMainCallQuery AS CallTbl
Where Format(CallTbl.CallDate,"dddd") <> 'Saturday' AND Format(CallTbl.CallDate,"dddd") <> 'Sunday'
AND (Format(CallTbl.StartTime,'hh:mm') >= '17:00' AND (CallTbl.StartTime,'hh:mm') < '9:00')

How to two select statements with sum functions in them

I'm trying to join these two tables and I get an error when I use any join. Union will work but returns all the values in two rows as opposed to 3 which I need. This is what I have so far and what it returns is below it. Any help would be great :)
select C.CustId ,SUM(Ia.Amount) as total
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE DATEPART(mm, I.InvoiceDate) = DATEPART(mm, DATEADD(mm, -1, getdate()))
and DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId
union
select C.CustId ,SUM(Ia.Amount) as total2
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE DATEPART(mm, I.InvoiceDate) = DATEPART(mm, DATEADD(mm, -2, getdate()))
and DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId
The returned result is below with the required result below that
Custid total
a 2
b 9
b 12
c 16
d 3
d 12
Custid total total2
a 2
b 9 12
c 16
d 3 12
select c.custid, c.total, c2.total2
from (select C.CustId ,SUM(Ia.Amount) as total
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE DATEPART(mm, I.InvoiceDate) = DATEPART(mm, DATEADD(mm, -1, getdate()))
and DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId) c
inner join
(select C.CustId ,SUM(Ia.Amount) as total2
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE DATEPART(mm, I.InvoiceDate) = DATEPART(mm, DATEADD(mm, -2, getdate()))
and DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId) c2 on c.custid = c2.custid
I think you are trying to have 2 columns of SUM of different Months. Here is what you can do:
Select C.CustId ,
Sum(Case DATEPART(mm, I.InvoiceDate)
When DATEPART(mm, DATEADD(mm, -1, getdate())) Then Ia.Amount
Else 0 End) As 'Total1',
Sum(Case DATEPART(mm, I.InvoiceDate)
When DATEPART(mm, DATEADD(mm, -2, getdate())) Then Ia.Amount
Else 0 End) As 'Total2'
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE
DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId
I am using Case to avoid the recursive join.
Since you are using MySQL, I would approach by implementing in-line sqlvariables (via my first "from" alias. The #FirstOfThisMonth is computed by subtracting whatever the current day of month is from the current date (less 1).
Ex: Today is April 3rd (3rd day of month). So, -3 = March 31... PLUS 1 brings back to April 1 of current month. Once that date is determined, I can now subtract an entire month for first of PREVIOUS month (March 1st), and subtract 2 months for Feb 1st.
Now that this complexity is done ONCE, we can use these variables instead of constant datepart extraction for month and year. Especially if you consider trying to do two months ago from Feb 10th. (First of current is Feb 1, one month back is Jan 1, two months back is Dec 1 of prior year).
NOW, I simply SUM() based on a case when condition.
if the Invoice Date is >= #TwoMonthsAgo AND LESS THAN #LastMonth, that goes into the two-months-ago total.
the next is Invoice Date >= #LastMonth AND LESS THAN #FirstOfThisMonth for last month's total.
Now, you have a rolling two-month window... If you wanted to go longer, just add another monthly variable reference and SUM() its criteria.
Finally the WHERE clause can only include invoices that are greater or equal to the #TwoMonthsAgo so it doesn't have to go through the entire database
select
C.CustId,
SUM( CASE when I.InvoiceDate >= #TwoMonthsAgo AND I.InvoiceDate < #LastMonth
then Ia.Amount else 0 end ) as TotalTwoMonthsAgo,
SUM( CASE when I.InvoiceDate >= #LastMonth AND I.InvoiceDate < #FirstOfThisMonth
then Ia.Amount else 0 end ) as TotalLastMonth
from
( select #FirstOfThisMonth := date_add( now(), INTERVAL -dayofmonth(now())+1 day ),
#LastMonth := date_add( #myDate, INTERVAL -1 month ),
#TwoMonthsAgo := date_add( #myDate, INTERVAL -2 month )) sqlvars,
Invoice I
inner join InvoiceAmtSummary Ia
on I.GUIDInvoice = Ia.GUIDInvoice
inner join Customer C
on C.GUIDCustomer = I.GUIDCustomer
WHERE
I.InvoiceDate >= #TwoMonthsAgo
AND I.InvoiceDate < #FirstOfThisMonth
group by
C.CustID