SQL Server : merge two rows into one - sql

I wrote the this T-SQL query:
SELECT
B.[Year], E.[Description] as GLClass,
D.Code, D.[GLDescription],
SUM(A.Jan) AS Jan,
SUM(A.Feb) AS Feb,
SUM(A.Mar) AS Mar,
SUM(A.Apr) AS Apr
FROM
GeneralLedgers A
INNER JOIN
Years B ON A.YearID = B.ID
INNER JOIN
CostCenters C ON A.CostCenterID = C.ID
INNER JOIN
GLCodes D ON A.GLCodeID = D.ID
INNER JOIN
GLClassificationTypes E ON D.GLClassificationTypeID = E.ID
WHERE
A.YearID = '13'
GROPU BY
B.[Year], D.Code, E.[Description], D.[GLDescription]
ORDER BY
D.Code, E.[Description]
It outputs this result:
I want to combine "Freight-in (Go) and Freight Savings" row into a single row and sum the value from column Jan, Feb, Mar, Apr. I was trying to used the Case When clause on the "Code" column to look for '401040110' and '441010300' but still can't figure it out.
How can this be accomplish?

Convert one of the 2 rows into the other for your groupings logic and the rest of the aggregation should work on top of that seamlessly.
SELECT B.[Year]
,E.[Description] AS GLClass
,case when D.Code = '441010300' then '401040110' else D.Code END Code
,case when D.Code = '441010300' then 'Freight-in (Go)' else D.[GLDescription] end [GLDescription]
,Sum(A.Jan) AS Jan
,Sum(A.Feb) AS Feb
,Sum(A.Mar) AS Mar
,Sum(A.Apr) AS Apr
FROM GeneralLedgers A
INNER JOIN Years B ON A.YearID = B.ID
INNER JOIN CostCenters C ON A.CostCenterID = C.ID
INNER JOIN GLCodes D ON A.GLCodeID = D.ID
INNER JOIN GLClassificationTypes E ON D.GLClassificationTypeID = E.ID
WHERE A.YearID = '13'
GROUP BY B.[Year]
, case when D.Code = '441010300' then '401040110' else D.Code END
, E.[Description]
, case when D.Code = '441010300' then 'Freight-in (Go)' else D.[GLDescription] end
ORDER BY 3,2

Related

Pull a separate column that matches the (min) of an aggregate function

It works well so far but I am stumped from here as I am brand new to this. This query finds the closest distance match, pairing up every item in the "FAILED" folder against everything that isn't in the "FAILED" folder.
There is a column "RouteID" in the "table p" that I want to match up with the min() aggregate.
I cannot process how to make the SELECT query simply show the associated "RouteID" column from tbl p but ultimately, I want to turn this into an update query that will SET a.Route = p.Route that is associated with the min()
Any help would be appreciated.
SELECT a.name, a.Reference1,
MIN(round(ACOS(COS(RADIANS(90-a.lat))
*COS(RADIANS(90-p.latpoint))
+SIN(RADIANS(90-a.lat))
*SIN(RADIANS(90-p.latpoint))
*COS(RADIANS(a.lon-p.longpoint)))
*3958.756,2)) AS 'DISTANCE'
FROM tblOrder AS a WITH (NOLOCK)
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrder b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS p ON 1=1
WHERE a.CustID = 180016
AND a.RouteID = 'FAILED'
AND a.StopType = 1
AND P.RouteID <> 'FAILED'
GROUP BY
a.name, a.Reference1
You can select them separately and then join them
SELECT c.name, c.Reference1, q.RouteID
FROM
(
SELECT a.name, a.Reference1,
MIN(round(ACOS(COS(RADIANS(90-a.lat))
*COS(RADIANS(90-p.latpoint))
+SIN(RADIANS(90-a.lat))
*SIN(RADIANS(90-p.latpoint))
*COS(RADIANS(a.lon-p.longpoint)))
*3958.756,2)) AS 'DISTANCE'
FROM tblOrder AS a WITH (NOLOCK)
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrder b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS p ON 1=1
WHERE a.CustID = 180016
AND a.RouteID = 'FAILED'
AND a.StopType = 1
AND P.RouteID <> 'FAILED'
GROUP BY
a.name, a.Reference1
) c
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrderRouteStops b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS q
ON q.routeID = c.DISTANCE

How to add date range filter to sub-query in SQL server?

I tried to create a report to get sales and collection data for a particular date range. But I received some data which are not belongs to that date period. How to solve this? Here my query
select a.DocDate as 'Order Date',f.DocDate as 'Collection Date',b.LineTotal as 'fbsales amount',a.SlpCode,a.CardCode,b.DocEntry,
sum(case when e.TaxCode = 'NBT2' then cast(e.LineTotal as decimal(22,8)) /1.02
when e.TaxCode = 'N2+V15' then (cast(e.LineTotal as decimal(22,8)) /1.173)
when e.TaxCode = 'VAT8' then (cast(e.LineTotal as decimal(22,8)) /1.08) else e.LineTotal end ) as 'fbdwnp without vat',b.LineNum
from ORDR a
left join RDR1 b on b.DocEntry = a.DocEntry
left join OSLP c on c.SlpCode = a.SlpCode
left join OITM d on d.ItemCode = b.ItemCode
left Join (select TaxCode,LineTotal,BaseEntry,BaseLine,DocEntry from DPI1 where [TargetType]<>'14') e on e.BaseEntry = b.DocEntry and e.BaseLine = b.LineNum
left Join (select DocEntry,DocDate From ODPI where CANCELED = 'N' and DocDate between '20190101' and '20191231') f on f.DocEntry = e.DocEntry
where a.CANCELED = 'N' and d.U_Product_Type = 'Facebook' and a.DocDate between '20190101' and '20191231' and a.SlpCode = 68
group by c.SlpName,a.SlpCode,b.LineTotal,d.DocEntry,a.CardCode,c.SlpName,b.DocEntry,a.DocDate,b.LineNum,f.DocDate
Highlighted row of following pic should only display 'fbsales amount' but it displays 'fbdwnp withoit vat' amount also.Because sales date is 30.12.2019 and collection date is 09.01.2020.
What can i do to overcome this issue
Try adding:
and a.DocDate is not null
to the query

T-SQL Programming Return table based on Variable

I've been trying to make this work for a while now but I can't figure what's wrong.
The function needs to return a table based on the input date. If the input year is not available in the database, the function needs to return the data for all the years, otherwise, it needs to return the data only for the specified year.
Maybe someone here can help.
I'm using the 2014 AdventureWorks Database.
Thanks
CREATE FUNCTION DBO.udf_fonction(#year INT)
RETURNS TABLE
AS
RETURN
IF #year IN (SELECT DISTINCT(YEAR(OrderDate)) AS Years
FROM Sales.SalesOrderHeader)
(
SELECT YEAR(A.OrderDate) AS SalesYear,
C.Name AS SalesTerritory,
D.Name AS SalesCountryName,
CASE(A.OnlineOrderFlag)
WHEN 1 THEN 'Online'
WHEN 0 THEN 'In-store'
END AS SalesType,
SUM(A.SubTotal) AS Montant
FROM sales.SalesOrderHeader A
INNER JOIN Sales.Customer B ON A.CustomerID = B.CustomerID
INNER JOIN Sales.SalesTerritory C ON B.TerritoryID = C.TerritoryID
INNER JOIN Person.CountryRegion D ON C.CountryRegionCode = D.CountryRegionCode
WHERE YEAR(A.OrderDate) = #year
GROUP BY YEAR(A.OrderDate), C.Name, D.Name, CASE(A.OnlineOrderFlag)
WHEN 1 THEN 'Online'
WHEN 0 THEN 'In-store'
END
)
ELSE (SELECT YEAR(A.OrderDate) AS SalesYear,
C.Name AS SalesTerritory,
D.Name AS SalesCountryName,
CASE(A.OnlineOrderFlag)
WHEN 1 THEN 'Online'
WHEN 0 THEN 'In-store'
END AS SalesType,
SUM(A.SubTotal) AS Montant
FROM sales.SalesOrderHeader A
INNER JOIN Sales.Customer B ON A.CustomerID = B.CustomerID
INNER JOIN Sales.SalesTerritory C ON B.TerritoryID = C.TerritoryID
INNER JOIN Person.CountryRegion D ON C.CountryRegionCode = D.CountryRegionCode
GROUP BY YEAR(A.OrderDate), C.Name, D.Name, CASE(A.OnlineOrderFlag)
WHEN 1 THEN 'Online'
WHEN 0 THEN 'In-store'
END
)
GO
WHERE YEAR(A.OrderDate) = #year
OR not exists (select 1 from sales.SalesOrderHeader where YEAR(OrderDate) = #year)
You are not returning a table anywhere

Having count returning zero rows when it should return something

SELECT
P.P_DESC AS P,
D.PD_NAME AS D,
D.GPE_NBR AS GPE,
D.GPE_GEN_NM,
D.GPE_2_ ,
D.GPE_4c ,
SUBSTR (TRIM(C.FILL_DATE__ID),1,6),
C.fill_Date__ID,
Prod.PD_DESC ,
DMC.M_A_NBR,
DMC.MAD_NBR ,
DMC.FT_NAME,
DMC.LA_NAME,
DDB.DATE_DATE,
CAST((CURRENT_DATE - DDB.DATE_DATE)/365.25 as Int) M_AGE_TODAY,
RXDOC.PB_FT_NAME || ' ' || RXDOC.PB_LA_NAME ,
RXDOC.PB_ID,
DT.D_TYPE_DESC ,
CASE WHEN SDL.GEPE IS NOT NULL THEN 'Y' ELSE 'N' END AS FLAG,
COUNT (C.PHR_C_ID) AS CCount,
SUM (C.AMT_PAID) AS Spend
FROM O_PHAR_C C
INNER JOIN _D D ON C.D__ID=D.D__ID
INNER JOIN _P P
ON C.P__ID = P.P__ID
AND C.P__ID = 00001
INNER JOIN _M_CURR DMC ON C.PB_M_CURR_ID = DMC.M_CURR_ID
INNER JOIN _M DM ON DM.M__ID = DMC.M__ID
INNER JOIN _DATE DDB ON DDB.DATE__ID = DM.BIRTH_DATE__ID
INNER JOIN _M_ELIG_CURR DMEC ON C.PB_M_ELIG_CURR_ID = DMEC.M_ELIG_CURR_ID
LEFT OUTER JOIN BA_PROD_LAB_OWN.specialtyDList SDL
ON D.GPE_NBR = SDL.GPE
AND SDL.EFF_END_DATE >= CURRENT_DATE
LEFT OUTER JOIN _PD Prod ON DMEC.PD__ID = Prod.PD__ID
LEFT OUTER JOIN _RX_PB RXDOC ON C.PB__ID=RXDOC.PB__ID
LEFT OUTER JOIN _PHAR_D_TYPE DT ON C.PHAR_D_TYPE__ID = DT.PHAR_D_TYPE__ID
WHERE C.fill_date__ID BETWEEN 20170201 AND 20170228
AND C.RE_I = 'N'
AND C.sR__ID IN (96,13,203)
GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14, 15, 16, 17, 18, 19
HAVING COUNT(*) >= 10;
I want to use this query to return instances of the C.PHR_C_ID that are more than or equal to 10. However, when I limit my select statement to that column I get the desired result but when I add all these columns to it 'having count' returns 0. There are more than zero records; I think there is something wrong with the query.
The problem is that when you add in your fields and GROUP BY them, you get a count of records for that distinct list of fields. You can probably switch to a QUALIFY statement instead. This will sum up the results by distinct C.PHR_C_ID ignoring the other fields, and then return any fields for that distinct C.PHR_C_ID which has a count(*) >= 10.
SELECT
P.P_DESC AS P,
D.PD_NAME AS D,
D.GPE_NBR AS GPE,
D.GPE_GEN_NM,
D.GPE_2_ ,
D.GPE_4c ,
SUBSTR (TRIM(C.FILL_DATE__ID),1,6),
C.fill_Date__ID,
Prod.PD_DESC ,
DMC.M_A_NBR,
DMC.MAD_NBR ,
DMC.FT_NAME,
DMC.LA_NAME,
DDB.DATE_DATE,
CAST((CURRENT_DATE - DDB.DATE_DATE)/365.25 as Int) M_AGE_TODAY,
RXDOC.PB_FT_NAME || ' ' || RXDOC.PB_LA_NAME ,
RXDOC.PB_ID,
DT.D_TYPE_DESC ,
CASE
WHEN SDL.GEPE IS NOT NULL THEN 'Y'
ELSE 'N'
END AS FLAG,
COUNT(*) OVER (PARTITION BY C.PHR_C_ID) AS CCount,
C.AMT_PAID AS Spend
FROM O_PHAR_C C
INNER JOIN _D D
ON C.D__ID=D.D__ID
INNER JOIN _P P
ON C.P__ID = P.P__ID
AND C.P__ID = 00001
INNER JOIN _M_CURR DMC
ON C.PB_M_CURR_ID = DMC.M_CURR_ID
INNER JOIN _M DM
ON DM.M__ID = DMC.M__ID
INNER JOIN _DATE DDB
ON DDB.DATE__ID = DM.BIRTH_DATE__ID
INNER JOIN _M_ELIG_CURR DMEC
ON C.PB_M_ELIG_CURR_ID = DMEC.M_ELIG_CURR_ID
LEFT OUTER JOIN BA_PROD_LAB_OWN.specialtyDList SDL
ON D.GPE_NBR = SDL.GPE
AND SDL.EFF_END_DATE >= CURRENT_DATE
LEFT OUTER JOIN _PD Prod
ON DMEC.PD__ID = Prod.PD__ID
LEFT OUTER JOIN _RX_PB RXDOC
ON C.PB__ID=RXDOC.PB__ID
LEFT OUTER JOIN _PHAR_D_TYPE DT
ON C.PHAR_D_TYPE__ID = DT.PHAR_D_TYPE__ID
WHERE
C.fill_date__ID BETWEEN 20170201 AND 20170228
AND C.RE_I = 'N'
AND C.sR__ID IN (96,13,203)
QUALIFY COUNT(*) OVER (PARTITION BY C.PHR_C_ID) >= 10;

How to display the accurate sum when using 2 inner joins?

I am trying to get the results:
Quote = 12345
Total Assets = 14
Total Ordered = 22
When I run the queries separately I get the correct results, but when I put the two queries together my results are off (this is because the tables b and c do not represent each other)
my table summaries are as follows:
Select a.Quote, SUM(b.Quantity) As 'Total Assets'
FROM a
INNER JOIN b ON b.aId = a.Id
GROUP By a.Quote
Result: 12345 : 14
Select a.Quote, SUM(c.Quantity) As 'Total Ordered'
FROM a
INNER JOIN c on c.aId = a.Id
GROUP By a.Quote
Result: 12345 : 22
However, when I put them together:
Select a.Quote, SUM(b.Quantity)As 'Total Assets',SUM(c.Quantity) As 'Total Ordered'
FROM a
INNER JOIN b on b.Aid = a.Id
INNER JOIN c on c.Aid = a.Id
GROUP BY a.Quote
Result 12345 : 56 : 308
I played with the group by but was never able to get the proper result. Any thoughts?
So far the solution I came up with is
With abc AS
(
Select a.Quote, SUM(b.Quantity) As 'Total Assets'
FROM a
INNER JOIN b ON b.aId = a.Id
GROUP By a.Quote
)
SELECT abc.* , SUM(c.Quantity) As ' Total Ordered'
FROM abc
INNER JOIN c ON c.aid = a.Id
GROUP BY (all in abc)
It doesn't seem like the best way to get the results though..
Maybe use Left JOIN. The INNER JOIN will repeat rows of b and c. Also, try to see the result of:
Select a.Quote, b.Quantity As 'Total Assets', c.Quantity As 'Total Ordered'
FROM a
INNER JOIN b on b.Aid = b.Id
INNER JOIN c on c.Aid = c.Id
GROUP BY a.Quote
And check if it's the right results that are computed. Then compare it against:
Select a.Quote, b.Quantity As 'Total Assets', c.Quantity As 'Total Ordered'
FROM a
LEFT JOIN b on b.Aid = b.Id
LEFT JOIN c on c.Aid = c.Id
GROUP BY a.Quote