T-SQL GROUP BY ISSUE WITH CASE STATEMENT - sql-server

I have a query with a CASE statement and I need to do a GROUP BY on the alias. I understand that cannot be done so I tried to use a subquery, but it is not working.
Here is the query that I was working on:
SELECT
a.Vendor,
a.Month_Sold
--SUM(sd.SBQSHP) AS Sales_Qty,
--SUM(sd.SBEPRC) AS Sales_Dlr
FROM
(SELECT
sd.IFPRVN AS Vendor,
vn.ACNAME AS Vendor_Name,
CASE
WHEN sd.SBINDT BETWEEN '2012-07-30' AND '2012-08-26' THEN 'August 2012'
WHEN sd.SBINDT BETWEEN '2012-08-27' AND '2012-09-30' THEN 'September 2012'
WHEN sd.SBINDT BETWEEN '2012-10-01' AND '2012-10-28' THEN 'October 2012'
WHEN sd.SBINDT BETWEEN '2012-10-29' AND '2012-11-25' THEN 'November 2012'
WHEN sd.SBINDT BETWEEN '2012-11-26' AND '2012-12-31' THEN 'December 2012'
WHEN sd.SBINDT BETWEEN '2013-01-01' AND '2013-01-27' THEN 'January 2013'
WHEN sd.SBINDT BETWEEN '2013-01-28' AND '2013-02-24' THEN 'Febuary 2013'
WHEN sd.SBINDT BETWEEN '2013-02-25' AND '2013-03-31' THEN 'March 2013'
END AS Month_Sold
FROM
dbo.SalesData sd
INNER JOIN dbo.S2K_VEND vn ON vn.ACVEND = sd.IFPRVN
WHERE
sd.SBINDT > '2012-07-29'
AND
sd.SBCLS IN ('1500')
AND
sd.SBDIV NOT IN ('4000')
)a
GROUP BY
a.Vendor,
a.Month_Sold
ORDER BY
a.Vendor,
a.Month_Sold
The two columns that are commented out need to be included somehow. Any suggestions?

Really, putting pretty labels on your date output should be a job for the presentation tier. FORMAT() in C# etc. is pretty powerful. Barring that, don't convert to pretty string labels until the last possible point, which will require one more layer:
SELECT
Vendor,
DATENAME(MONTH, Month_Sold) + ' ' + RTRIM(YEAR(Month_Sold)),
Sales_Qty,
Sales_Dlr
FROM
(
SELECT
Vendor,
Month_Sold,
SUM(SBQSHP) AS Sales_Qty,
SUM(SBEPRC) AS Sales_Dlr
FROM
(
SELECT
sd.IFPRVN AS Vendor,
vn.ACNAME AS Vendor_Name, -- why is this here?
CASE
WHEN sd.SBINDT BETWEEN '2012-07-30' AND '2012-08-26' THEN '2012-08-01'
WHEN sd.SBINDT BETWEEN '2012-08-27' AND '2012-09-30' THEN '2012-09-01'
...
WHEN sd.SBINDT BETWEEN '2013-01-28' AND '2013-02-24' THEN '2013-02-01'
WHEN sd.SBINDT BETWEEN '2013-02-25' AND '2013-03-31' THEN '2013-03-01'
END AS Month_Sold
FROM dbo.SalesData sd
INNER JOIN dbo.S2K_VEND vn
ON vn.ACVEND = sd.IFPRVN
WHERE sd.SBINDT > '2012-07-29'
AND sd.SBCLS IN ('1500')
AND sd.SBDIV NOT IN ('4000')
) AS a
GROUP BY Vendor, Month_Sold
) AS b
ORDER BY
Vendor,
Month_Sold;

Simply select the values you need to aggregate in your subquery with alias "a"
Add to subquery "a" select statement:
SELECT
sd.IFPRVN AS Vendor,
vn.ACNAME AS Vendor_Name,
sd.SBQSHP,
sd.SBEPRC
CASE
...
Uncomment SUM statements at top level select statement but change alias from "sd" to "a"
SUM(a.SBQSHP) AS Sales_Qty,
SUM(a.SBEPRC) AS Sales_Dlr

Related

Join 3 temp tables into 1 result table by merging columns

I have a huge query that creates a cte of warehouses and uses this to create 3 more cte's with the same column names.
below is my T-Sql query:
With WhList AS (SELECT Company, Warehouse FROM
CCWMS.dbo.WMSWarehouse_Control),
CoB AS (SELECT 'B' AS Company, B_IMB.Warehouse, B_IMB.StockCode, B_IMB.Bin, B_IMB.QtyOnHand1 AS QtyOnHand, B_IMB.SoQtyToShip, B_IMB.LastReceiptDate,B_IMB.OnHold FROM SysproCompanyB.dbo.InvMultBin AS B_IMB RIGHT JOIN WhList As WL ON B_IMB.Warehouse=WL.Warehouse WHERE QtyOnHand1 <> 0),
CoX AS (SELECT 'X' AS Company, X_IMB.Warehouse, X_IMB.StockCode, X_IMB.Bin, X_IMB.QtyOnHand1 AS QtyOnHand, X_IMB.SoQtyToShip, X_IMB.LastReceiptDate,X_IMB.OnHold FROM SysproCompanyX.dbo.InvMultBin AS X_IMB RIGHT JOIN WhList As WL ON X_IMB.Warehouse=WL.Warehouse WHERE QtyOnHand1 <> 0),
CoH AS (SELECT 'H' AS Company, H_IMB.Warehouse, H_IMB.StockCode, H_IMB.Bin, H_IMB.QtyOnHand1 AS QtyOnHand, H_IMB.SoQtyToShip, H_IMB.LastReceiptDate,H_IMB.OnHold FROM SysproCompanyH.dbo.InvMultBin AS H_IMB RIGHT JOIN WhList As WL ON H_IMB.Warehouse=WL.Warehouse WHERE QtyOnHand1 <> 0)
I need to compile these three cte's into one result set.
Any way I might be able to achieve this. I have thought about PIVOT but cant seem to wrap my head around how to do this.
I think you are looking for union all of all the results... What do you mean by combining the results?
Are you looking something like below?
SELECT Company, Warehouse FROM (
SELECT 'B' AS Company, B_IMB.Warehouse, B_IMB.StockCode, B_IMB.Bin, B_IMB.QtyOnHand1 AS QtyOnHand, B_IMB.SoQtyToShip, B_IMB.LastReceiptDate,B_IMB.OnHold FROM SysproCompanyB.dbo.InvMultBin AS B_IMB RIGHT JOIN WhList As WL ON B_IMB.Warehouse=WL.Warehouse WHERE QtyOnHand1 <> 0
UNION ALL
SELECT 'X' AS Company, X_IMB.Warehouse, X_IMB.StockCode, X_IMB.Bin, X_IMB.QtyOnHand1 AS QtyOnHand, X_IMB.SoQtyToShip, X_IMB.LastReceiptDate,X_IMB.OnHold FROM SysproCompanyX.dbo.InvMultBin AS X_IMB RIGHT JOIN WhList As WL ON X_IMB.Warehouse=WL.Warehouse WHERE QtyOnHand1 <> 0
UNION ALL
SELECT 'H' AS Company, H_IMB.Warehouse, H_IMB.StockCode, H_IMB.Bin, H_IMB.QtyOnHand1 AS QtyOnHand, H_IMB.SoQtyToShip, H_IMB.LastReceiptDate,H_IMB.OnHold FROM SysproCompanyH.dbo.InvMultBin AS H_IMB RIGHT JOIN WhList As WL ON H_IMB.Warehouse=WL.Warehouse WHERE QtyOnHand1 <> 0
) A
I solved it. I cant believe I didn't think of this. Answer as follows:
--CTE's end here.
SELECT * FROM CoB
UNION
SELECT * FROM CoX
UNION
SELECT * FROM CoH
Thanks though

How to pivot and get total amount each month

I have data like :
My table
My final results should be like this:
My SQL Statement:
SELECT 'Q'+cast([Month_Quarter] as varchar) Month_Quarter,COALESCE([Zugänge],0) Zugänge,COALESCE([Abgänge],0) Abgänge
FROM
(
SELECT DATEPART(QUARTER,[Monat]) [Month_Quarter],
[Zu-, Abgang],
Count(DISTINCT [Projektdefinition DB]) NoProjects
FROM AbZugänge
GROUP BY DATEPART(QUARTER,[Monat]), [Zu-, Abgang]
) proj
PIVOT (SUM(NoProjects) FOR [Zu-, Abgang] IN (Zugänge, Abgänge)) As pvt
WHERE [Month_Quarter] is not null
ORDER BY Month_Quarter
BUT with this statement I am getting the results without the Amount column Zugang and column Abgang:
How can I edit the statement to get the aggregation amount columns?
I suppose you can just wrap your query inside another select statement, then use GROUP BY. Something like this:
SELECT Month, SUM(ISNULL(column_name,0))
FROM (Your Query in here)
GROUP BY Month
Not sure I understand the point of the PIVOT in your original query. This looks like a typical aggregate is all that is required. See if this is what you need.
SELECT DATENAME(MONTH,Monat) [Month]
, sum(case when [Zu-, Abgang] = 'Zugänge' then [Zu-, Abgang] else 0 end) as Zugänge
, SUM(case when [Zu-, Abgang] = 'Abgänge' then [Zu-, Abgang] else 0 end) as Abgänge
, SUM([GWU aktuell]) as [GWU Total]
, SUM([GWU Planung aktuell]) AS [Plan Total]
, COUNT(DISTINCT [Projektdefinition DB]) NoProjects
FROM AbZugänge
group by DATENAME(MONTH,Monat)

Sql server XML methods are not allowed in a GROUP BY clause

i just issue a group by where i specify xml data then i got error XML methods are not allowed in a GROUP BY clause.
here is my sql
SELECT HourSheetID,(MAX(RowID)+1) as "RowID",
XMLData.value('(Log/EntryDate)[1]','datetime') as EntryDate,
XMLData.value('(Log/SpecialistID)[1]','int') as SpecialistID,
XMLData.value('(Log/HoursData)[1]','decimal(18,2)') as HoursData,
XMLData.value('(Log/UpdatedBy)[1]','varchar(max)') as UpdatedBy,
XMLData.value('(Log/Options)[1]','varchar(max)') as Options,
logdate
FROM dbo.EditedHourSheetLog
GROUP BY HourSheetID,
XMLData.value('(Log/EntryDate)[1]','datetime'),
XMLData.value('(Log/SpecialistID)[1]','int'),
XMLData.value('(Log/HoursData)[1]','decimal(18,2)'),
XMLData.value('(Log/UpdatedBy)[1]','varchar(max)'),
XMLData.value('(Log/Options)[1]','varchar(max)'),
logdate
if i can not specify xml data in group by cluase then what other option is available....please guide. thanks
This way i achieve my task
ALTER PROC sp_HourSheetLog
(
#StartDate VARCHAR(8),
#EndDate VARCHAR(8)
)
AS
SELECT B.ID
,A.RowID
,B.EntryDate
,B.Name
,B.HoursData
,B.UpdatedBy
,Options=(CASE B.Options
WHEN 'rdLeave' THEN 'Leave'
WHEN 'rdsick' THEN 'Sick'
WHEN 'rdSalvage' THEN 'Salvage'
WHEN 'rdCSRDuty' THEN 'CSR Duty'
WHEN 'rdShippingSales' THEN 'Shipping and Sales'
WHEN 'rdEOL' THEN 'EOL'
WHEN 'rdTraining' THEN 'Training'
WHEN 'rdOther' THEN 'Other'
END)
,B.ModDate
FROM (
(
SELECT HourSheetID,(MAX(RowID)+1) as "RowID"
FROM EditedHourSheetLog l,EditedHourSheet h
GROUP BY HourSheetID
) A
JOIN
(
SELECT h.ID
,s.Name
,h.EntryDate
,h.HoursData
,h.Options
,h.UpdatedBy
,h.ModDate from EditedHourSheet h
LEFT JOIN Specialists s
ON h.SpecialistID=s.SpecialistID
) B
ON A.HourSheetID=B.ID
)
WHERE Convert(Varchar,ModDate,112)>=#StartDate AND
Convert(Varchar,ModDate,112)<=#EndDate
UNION
(
Select HourSheetID as ID,RowID,
XMLData.value('(Log/EntryDate)[1]','datetime') as EntryDate,
--XMLData.value('(Log/SpecialistID)[1]','int') as SpecialistID,
s.Name,
XMLData.value('(Log/HoursData)[1]','decimal(18,2)') as HoursData,
CAST(XMLData.value('(Log/UpdatedBy)[1]','varchar(max)') AS VARCHAR(MAX)) UpdatedBy,
Options=(CASE XMLData.value('(Log/Options)[1]','varchar(max)')
WHEN 'rdLeave' THEN 'Leave'
WHEN 'rdsick' THEN 'Sick'
WHEN 'rdSalvage' THEN 'Salvage'
WHEN 'rdCSRDuty' THEN 'CSR Duty'
WHEN 'rdShippingSales' THEN 'Shipping and Sales'
WHEN 'rdEOL' THEN 'EOL'
WHEN 'rdTraining' THEN 'Training'
WHEN 'rdOther' THEN 'Other'
END),
LogDate as ModDate
FROM EditedHourSheetLog h
LEFT JOIN Specialists s
ON h.XMLData.value('(Log/SpecialistID)[1]','int')=s.SpecialistID
WHERE Convert(Varchar,LogDate,112)>=#StartDate AND
Convert(Varchar,LogDate,112)<=#EndDate
)
ORDER BY ID,RowID DESC
--sp_HourSheetLog '20140101','20140326'
You can use a derived table and do the group by in the main query.
SELECT T.HourSheetID,
MAX(T.RowID)+1 as RowID,
T.EntryDate,
T.SpecialistID,
T.HoursData,
T.UpdatedBy,
T.Options,
T.logdate
FROM (
SELECT HourSheetID,
RowID,
XMLData.value('(Log/EntryDate)[1]','datetime') as EntryDate,
XMLData.value('(Log/SpecialistID)[1]','int') as SpecialistID,
XMLData.value('(Log/HoursData)[1]','decimal(18,2)') as HoursData,
XMLData.value('(Log/UpdatedBy)[1]','varchar(max)') as UpdatedBy,
XMLData.value('(Log/Options)[1]','varchar(max)') as Options,
logdate
FROM dbo.EditedHourSheetLog
) AS T
GROUP BY T.HourSheetID,
T.EntryDate,
T.SpecialistID,
T.HoursData,
T.UpdatedBy,
T.Options,
T.logdate

How execute/open multiple SQL statements in 1 go with ODBC / SQL-Server

What I'm basically trying to do is fire off multiple SQL statements in one go.
This works fine as long as they don't return results.
What I want to do is make a temporary table fill it and join it on my existing data:
CREATE TABLE #JaarMaandTable(jaarm int,maandm int)
INSERT INTO #JaarMaandTable (jaarm,maandm) VALUES (2013,9), (2013,10), (2013,11)
SELECT jaarm,maandm, kr.*
FROM #JaarMaandTable jm
LEFT JOIN (
SELECT DATEPART(Month, datum) as maand, DATEPART(Year, datum) as jaar ,count(*) as regels mytable
FROM agenda
WHERE datum >= '20130901'
AND datum <= '20131130'
GROUP BY DATEPART(Year, datum), DATEPART(Month, datum)
)kr ON jm.jaarm = kr.jaar AND jm.maandm = kr.maand ORDER BY jaarm, maandm
This is to make use of a temp table to split up results in months even when there's no data for those months.
It works fine in query analyser.
When I try to use "open" on this query, it tells me it doesn't return a cursor.
When I "execsql" it, it won't return results.
When I split it up, it immediately forgets the #temptable.
You can write the query using a with statement, to avoid the need for a temporary table:
with JaarMaandTable(jaarm int,maandm int) as (
select 2013, 9 union all
select 2013, 10 union all
select 2013, 11
)
SELECT jaarm,maandm, kr.*
FROM JaarMaandTable jm
LEFT JOIN (
SELECT DATEPART(Month, datum) as maand, DATEPART(Year, datum) as jaar ,count(*) as regels mytable
FROM agenda
WHERE datum >= '20130901'
AND datum <= '20131130'
GROUP BY DATEPART(Year, datum), DATEPART(Month, datum)
)kr ON jm.jaarm = kr.jaar AND jm.maandm = kr.maand ORDER BY jaarm, maandm

in grouping getting duplicate records

I want to filter records on the basis of month. Requirement is in month how much projects are in "completed, pending, started etc" status. This is my query but i am getting duplicate records.
SELECT distinct
convert(varchar(7), w.ExpectedStartDate, 126) AS StatusOfMonth,
COUNT(w.StatusTypeId) AS StatusCount,
w.StatusTypeId,
st.StatusTypeName
FROM Table1 w
LEFT OUTER JOIN StatusType st ON st.StatusTypeId = w.StatusTypeId
WHERE CONVERT(VARCHAR(20), w.ExpectedStartDate, 103) BETWEEN '10/01/2011' AND '14/04/2011'
GROUP BY ExpectedStartDate, w.StatusTypeId, st.StatusTypeName
Please see image to clarify what i want. Please let me know how can i get correct results.
Looks like your grouping by the date, not by the month or by the status of month
Group by
DATEPART(M, ExpectedStartDate)
or
convert(varchar(7), w.ExpectedStartDate, 126)
instead of just ExpectedStartDate
EDIT
In response the comment:
Try getting rid of
convert(varchar(7), w.ExpectedStartDate, 126) AS StatusOfMonth
and just try it like this:
SELECT
convert(varchar, datepart(yyyy, w.ExpectedStartDate)) + '-' + CONVERT(varchar(3), DATENAME(month, w.ExpectedStartDate)),
w.StatusTypeId,
st.StatusTypeName,
COUNT(w.StatusTypeId) AS StatusCount
FROM
Table1 w LEFT OUTER JOIN
StatusType st ON st.StatusTypeId = w.StatusTypeId
WHERE
w.ExpectedStartDate BETWEEN '1/10/2011' AND '04/14/2011'
GROUP BY
datepart(M, w.ExpectedStartDate),
datepart(yyyy, w.ExpectedStartDate),
w.StatusTypeId,
st.StatusTypeName

Resources