Group by in subquery? - sql

I need some help with group by in subquery. Can you help me to solve this grouping problem:
select
DATEPART(wk, oh. ExportDate) as wk,
DATEPART(dw,oh.ExportDate) as day,
ro.Name,
Pallets = sum(oh.Pallets),
Box = (select count(Number) from OrderItem where ID_OrderHead = oh.Id)
from
OrderHeadPDAEvent ohpe
left outer join OrderHead oh on oh.Id = ohpe.ID_OrderHeader
left outer join Route ro on oh.ID_Route = ro.ID
where
ID_Route = '00000000-0000-0000-0000-000000000000'
and
oh.ExportDate > dbo.GetStartOfDay('2012-08-01 14:35:00.000' )
and
oh.ExportDate < dbo.GetEndOfDay('2013-08-08 14:35:00.000')
group by
oh.ExportDate, ro.Name, oh.ID
order by
DATEPART(wk, oh. ExportDate)
And data looks like this:
26 3 Standard - Uten rute 5 49
26 3 Standard - Uten rute 2 45
26 3 Standard - Uten rute 2 38
26 3 Standard - Uten rute 1 26
26 3 Standard - Uten rute 1 64
26 3 Standard - Uten rute 2 45
26 3 Standard - Uten rute 3 64
I want to sum all rows to get them in 1 row only.

Try this one -
SELECT
DATEPART(wk, oh.ExportDate) AS wk
, DATEPART(dw, oh.ExportDate) AS day
, ro.name
, Pallets = SUM(oh.Pallets)
, Box = SUM(n)
FROM dbo.OrderHeadPDAEvent ohpe
LEFT JOIN dbo.OrderHead oh ON oh.ID = ohpe.ID_OrderHeader
LEFT JOIN dbo.[Route] ro ON oh.ID_Route = ro.ID
LEFT JOIN (
SELECT n = COUNT(number), ID_OrderHead
FROM dbo.OrderItem
GROUP BY ID_OrderHead
) t ON t.ID_OrderHead = oh.ID
WHERE ID_Route = '00000000-0000-0000-0000-000000000000'
AND oh.ExportDate BETWEEN
dbo.GetStartOfDay('2012-08-01 14:35:00.000')
AND
dbo.GetEndOfDay('2013-08-08 14:35:00.000')
GROUP BY
oh.ExportDate
, ro.name
ORDER BY wk

Related

Join and max date with null values

I need to return the most recent (max)date for a patient_ID where a vital value exists - it's not simply the max. encounter date for the patient_ID, it must have a corresponding vital value. I also only want encounters where vitals value <>'' and Date >= '2020-01-01' and vital_ID = 232268.
Encounters (enc)
Patient_ID
Encounter_ID
Date
1
11
1/4/2020
1
12
1/15/2020
1
13
3/6/2020
2
14
1/12/2020
3
15
3/16/2020
3
16
4/19/2020
4
17
6/2/2020
4
18
6/12/2020
4
19
9/1/2020
Vitals
Encounter_ID
Vital_ID
Value
11
232268
4.8
12
232268
4.6
14
232268
3.1
16
232268
3.2
17
232268
4.1
18
232268
4.7
Desired Outcome
Patient_ID
Encounter_ID
Date
Value
1
12
3/6/2020
4.6
2
14
1/12/2020
3.1
3
16
4/19/2020
3.2
4
18
9/1/2020
4.7
I tried this, but it returned only the vitals_encounter_ID IF it = max(date) of the encounter for the patient_ID (so did not include patient_ID if vitals were not taken on the max(date) - for instance, it negates patient_ID 1 all together because vitals weren't taken on encounter_ID 13:
select v.encounterID, e.patientID, e.date, v.value, v.vitalID
from vitals v
left join enc e on
e.encounterID = v.encounterID and
v.vitalID = 232268 and
v.value <> '' and
e.date = (select max(date) from enc where patientID=e.patientID)
where e.date >= '2020-01-01'
Cognos 8. I'm new, so please don't eat me alive...
If I follow you correctly, you need the two tables in the correlated subquery:
select v.encounterid, e.patientid, e.date, v.value, v.vitalid
from enc e
inner join vitals v on v.encounterid = e.encounterid
where
v.vitalid = 232268
and v.value <>''
and e.date = (
select max(e1.date)
from enc e1
inner join vitals v1 on v1.encounterid = e1.encounterid
where
e1.patientid = e.patientid
and v1.vitalid = v.vitalid
and v1.value <> ''
and e.date >= '2020-01-01'
)
I don't know if Cognos supports window functions. But if it does, the query can be much simpler phrased:
select *
from (
select v.encounterid, e.patientid, e.date, v.value, v.vitalid,
row_number() over(partition by e.patientid order by e.date)
from enc e
inner join vitals v on v.encounterid = e.encounterid
where v.vitalid = 232268 and v.value <> ''
) t
where rn = 1

Calculate Average of each month in SQL Server

I'm having two tables
Promo
ID | Name
---+---------
1 Front
2 Middle
3 Back
PromoRate
ID | Date | Rate | PromoID
---+------------+------+----------
1 2020-01-01 100 1
2 2020-01-02 200 1
3 2020-02-03 300 1
4 2020-02-01 150 2
5 2020-01-02 250 2
6 2020-03-03 350 2
7 2020-03-01 200 3
8 2020-01-02 400 3
9 2020-01-03 600 3
I want to calculate average. Something like this
Name | Avg(Jan) | Avg(Feb) | Avg(Mar)
-------+----------+----------+----------
Front 150 300 NULL
Middle 250 150 350
Back 500 NULL 200
Like pivot or something.
Please help me. Thanks in advance
What I've tried:
SELECT * FROM
(
SELECT P.ID, P.Name, AVG(Rate) AS 'AVG' FROM PromoRate PR
INNER JOIN Promo P ON P.ID = PR.ProfileID
WHERE MONTH(Date) = MONTH(GETDATE())
GROUP BY P.Name, P.ID
) M1
LEFT JOIN
(
SELECT P.ID, P.Name, AVG(Rate) AS 'AVG' FROM PromoRate PR
INNER JOIN Promo P ON P.ID = PR.ProfileID
WHERE MONTH(Date) = MONTH(GETDATE()) + 1
GROUP BY P.Name, P.ID
) M2 ON M1.ID = M2.ID
LEFT JOIN
(
SELECT P.ID, P.Name, AVG(Rate) AS 'AVG' FROM PromoRate PR
INNER JOIN Promo P ON P.ID = PR.ProfileID
WHERE MONTH(Date) = MONTH(GETDATE()) + 2
GROUP BY P.Name, P.ID
) M3 ON M2.ID = M3.ID
But it's not working as expected
You need to group on Month(Date), I'd also use DateAdd rather than month(GetDate()) + 2. You can then use the one query rather than joining on 3 queries as you're going to run into trouble when you cross the year line, or if you have multiple years. E.g. running it in November will also return the results for January that year and next year.
If this is part of a stored procedure I'd also recommend creating an #startdate and #enddate variable and setting those up first.
declare #start datetime
declare #end datetime
select #start = convert(date,GETDATE()), #end = convert(date, DATEADD(month, 2, GETDATE()))
SELECT P.ID, P.Name, AVG(Rate) AS 'AVG' FROM PromoRate PR
INNER JOIN Promo P ON P.ID = PR.ProfileID
WHERE Convert(date, Date) > #start and convert(date, date) < #end
GROUP BY P.Name, P.ID, MONTH(Date)
ETA: You also need to return your month so that you can populate your pivot table.

SQL Splitting SUM Rows into Columns based on Dates

I am trying to SUM values into columns based on dates.
This is my current SQL
SELECT DISTINCT
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM') AS Month,
dbo.DR_ACCS.NAME,
SUM(dbo.DR_INVLINES.QUANTITY * dbo.STOCK_ITEMS.X_LITERAGE) AS SUMQTY,
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'yy') AS Year
FROM
dbo.DR_INVLINES
INNER JOIN
dbo.DR_TRANS ON dbo.DR_INVLINES.HDR_SEQNO = dbo.DR_TRANS.SEQNO
INNER JOIN
dbo.STOCK_ITEMS ON dbo.DR_INVLINES.STOCKCODE = dbo.STOCK_ITEMS.STOCKCODE
INNER JOIN
dbo.DR_ACCS ON dbo.DR_INVLINES.ACCNO = dbo.DR_ACCS.ACCNO
GROUP BY
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'yy'),
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM'),
dbo.STOCK_ITEMS.STOCKGROUP, dbo.DR_ACCS.NAME
HAVING
(dbo.STOCK_ITEMS.STOCKGROUP = 3)
This query returns this result set:
Mth Name SUMQTY Year
-----------------------------
Apr Company 1 1000 16
Apr Company 2 30790.4 16
Apr Company 3 1840 16
Apr Company 1 6502.9 17
Apr Company 2 2000 17
Apr Company 3 1000 17
What I am trying to achieve is
Mth Name 2016 2017
-------------------------------
Apr Company 1 800 200
Apr Company 2 15000 13000
Apr Company 3 600 569
Apr Company 1 5000 1500
Apr Company 2 2000 1986
Apr Company 3 1000 2543
Can someone please help with this..... I have been racking my brain for ages on this one ;-)
If I understand your question, you wanted to display YEAR as column,
SELECT FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM') AS Month,
dbo.DR_ACCS.NAME,
SUM(CASE WHEN YEAR(dbo.DR_INVLINES.TRANSDATE) = 2016
THEN dbo.DR_INVLINES.QUANTITY * dbo.STOCK_ITEMS.X_LITERAGE
ELSE 0
END ) AS [2016],
SUM(CASE WHEN YEAR(dbo.DR_INVLINES.TRANSDATE) = 2017
THEN dbo.DR_INVLINES.QUANTITY * dbo.STOCK_ITEMS.X_LITERAGE
ELSE 0
END ) AS [2017]
FROM dbo.DR_INVLINES
INNER JOIN dbo.DR_TRANS
ON dbo.DR_INVLINES.HDR_SEQNO = dbo.DR_TRANS.SEQNO
INNER JOIN dbo.STOCK_ITEMS
ON dbo.DR_INVLINES.STOCKCODE = dbo.STOCK_ITEMS.STOCKCODE
INNER JOIN dbo.DR_ACCS
ON dbo.DR_INVLINES.ACCNO = dbo.DR_ACCS.ACCNO
WHERE dbo.STOCK_ITEMS.STOCKGROUP = 3
GROUP BY FORMAT(dbo.DR_INVLINES.TRANSDATE, 'yy'),
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM'),
dbo.STOCK_ITEMS.STOCKGROUP,
dbo.DR_ACCS.NAME
Have you tried group by?
SELECT FORMAT(il.TRANSDATE, 'MMM') AS Month, a.NAME,
SUM(CASE WHEN year(il.TRANSDATE) = 2016 THEN anil.QUANTITY * si.X_LITERAGE END) AS SUMQTY_2017,
SUM(CASE WHEN year(il.TRANSDATE) = 2017 THEN anil.QUANTITY * si.X_LITERAGE END) AS SUMQTY_2016
FROM dbo.DR_INVLINES il INNER JOIN
dbo.DR_TRANS t
ON il.HDR_SEQNO = t.SEQNO INNER JOIN
dbo.STOCK_ITEMS si
ON il.STOCKCODE = si.STOCKCODE INNER JOIN
dbo.DR_ACCS a
ON il.ACCNO = a.ACCNO
WHERE si.STOCKGROUP = 3
GROUP BY FORMAT(il.TRANSDATE, 'MMM'), a.NAME;
Note the changes:
Table aliases make the query easier to write and to read.
The having clause is on an unaggregated column, so it should be a where clause.
You had an extra column in the group by.
I would recommend using datepart() or datename() over format().

Increment row depending on value of another column

I have a sql query below, where dtMontno could start from any month and am adding Row column manually as below :
SELECT COUNT(*) as count,
MONTH(TourTbl.DT_Started) as dtMonthno,
DATENAME(YYYY, TourTbl.DT_Started) as dtYear,
row_number() over (order by DATENAME(YYYY, TourTbl.DT_Started) asc,
MONTH(TourTbl.DT_Started) asc ) as Row
FROM TourTbl
INNER JOIN BranchTbl ON TourTbl.BranchID = BranchTbl.BranchID
INNER JOIN AgencyTbl on AgencyTbl.AgencyID = BranchTbl.AgencyID
WHERE Cancelled = 0 AND
(TourTbl.DT_Started >= '2010/03/15' and
TourTbl.DT_Started <= '2012/03/15') AND
AgencyTbl.AgencyID in ( 245 ) and
BranchRODID > 0
group by datename(M, TourTbl.DT_Started),
DATENAME(YYYY, TourTbl.DT_Started),
MONTH(TourTbl.DT_Started)
order by dtYear asc, dtMonthno asc
now my result is :
count dtMonthno dtYear Row
6 5 2011 1
8 6 2011 2
2 7 2011 3
23 8 2011 4
126 9 2011 5
101 10 2011 6
85 11 2011 7
92 12 2011 8
115 1 2012 9
102 2 2012 10
48 3 2012 11
Is there any way to start the Row column depending on the dtMonthno and increment by one in the example above would start from 5 and end in 15?
Thanks
Try changing the derivation of Row to:
row_number() over (order by YEAR(TourTbl.DT_Started) asc,
MONTH(TourTbl.DT_Started) asc ) +
min(YEAR(TourTbl.DT_Started)*12+MONTH(TourTbl.DT_Started)-1) OVER () % 12 as Row
You can add month of first DT_Started date:
SELECT COUNT(*) as count,
MONTH(TourTbl.DT_Started) as dtMonthno,
DATENAME(YYYY, TourTbl.DT_Started) as dtYear,
row_number() over (order by DATENAME(YYYY, TourTbl.DT_Started) asc,
MONTH(TourTbl.DT_Started) asc )
+ substring(min(DATENAME(YYYY, [TourTbl].DT_Started) + right ('0' + str (MONTH([TourTbl].DT_Started), 2), 2)) over (), 5, 2) - 1 as Row
FROM TourTbl
INNER JOIN BranchTbl ON TourTbl.BranchID = BranchTbl.BranchID
INNER JOIN AgencyTbl on AgencyTbl.AgencyID = BranchTbl.AgencyID
WHERE Cancelled = 0 AND
(TourTbl.DT_Started >= '2010/03/15' and
TourTbl.DT_Started <= '2012/03/15') AND
AgencyTbl.AgencyID in ( 245 ) and
BranchRODID > 0
group by datename(M, TourTbl.DT_Started),
DATENAME(YYYY, TourTbl.DT_Started),
MONTH(TourTbl.DT_Started)
order by dtYear asc, dtMonthno asc
I would truncate the dates to months and group by those values, then obtain years, months and row numbers based on the truncated dates:
SELECT
COUNT(*) AS count,
MONTH(GroupMonth) AS dtMonthno,
DATENAME(YYYY, GroupMonth) AS dtYear, /* why do you want year as a string? */
ROW_NUMBER() OVER (ORDER BY GroupMonth) + MONTH(MIN(GroupMonth) OVER ()) - 1 AS Row
FROM (
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, TourTbl.DT_Started), 0) AS GroupMonth
FROM TourTbl
INNER JOIN BranchTbl ON TourTbl.BranchID = BranchTbl.BranchID
INNER JOIN AgencyTbl on AgencyTbl.AgencyID = BranchTbl.AgencyID
WHERE Cancelled = 0 AND
(TourTbl.DT_Started >= '2010/03/15' and
TourTbl.DT_Started <= '2012/03/15') AND
AgencyTbl.AgencyID in ( 245 ) and
BranchRODID > 0
) s
GROUP BY GroupMonth

SQL - Comparing and Grouping Data on multiple rows

I'm trying to query my database to find which products sold less in October than in either November or December.
I thought something like below would do it but I have a feeling the sub query will be returning the mininimum quantity for the whole database rather than for the specific product.
There must be some way of doing this using GROUP BY but I cant figure it out.
SELECT Category, Product
FROM Sales
WHERE SaleQuantity < (SELECT MIN(SaleQuantity)
FROM Sales
WHERE MonthNumber > 10)
AND MonthNumber = 10
Data looks like:
Category Product MonthNumber SaleQuantity
---------- ----------- ------------- -----------
11 14 10 210
11 14 11 200
11 14 12 390
15 12 10 55
15 12 11 24
17 12 12 129
19 10 10 12
Thanks.
try something like this
SELECT Category,
Product,
SUM( s.SaleQuantity ) AS saleOcotber,
SUM( ISNULL( son.SaleQuantity, 0 ) ) AS saleNovember,
SUM( ISNULL( sod.SaleQuantity, 0 ) ) AS saleDecember
FROM Sales s
LEFT OUTER JOIN Sales son ON son.Category = s.Category
AND son.Product = s.Product
AND son.MonthNumber = 11
LEFT OUTER JOIN Sales sod ON sod.Category = s.Category
AND sod.Product = s.Product
AND sod.MonthNumber = 11
WHERE s.MonthNumber = 10
GROUP BY Category,Product
WHERE SUM( s.SaleQuantity ) < SUM( ISNULL( son.SaleQuantity, 0 ) )
OR SUM( s.SaleQuantity ) < SUM( ISNULL( sod.SaleQuantity, 0 ) )
I have no tested this select but i think it will do the job if there is something not clear
please ask
Best Regards,
Iordan
PS. I presume you are using some version of MSSQL if not try to rewrite it by yourself int SQL you are using
Your table already appears to be summarised by Category, Product and MonthNumber, for SalesQuantity. If so, try this:
select distinct Category, Product
from Sales s11_12
where MonthNumber in (11,12) and
not exists (select null
from Sales s10
where s10.Category = s11_12.Category and
s10.Product = s11_12.Product and
s10.SalesQuantity >= s11_12.SalesQuantity)