How can I rewrite this query without repeating SELECT subqueries - sql

I have written a query like this. It is working and giving me the result which I wanted.
I have a SELECT query to get CAR_AMOUNT and HOTEL_AMOUNT.
But, I have to repeat the same SELECT query to get the SUM of both. I am not able to use alias name. How can I avoid this?
SELECT B.EMPLOYEE_ID,
(select SUM(AMOUNT)
FROM travel_reimbursements_items
WHERE type = 'CAR'
AND travel_request_no = B.travel_request_no
AND STATUS='APPROVED') as CAR_AMOUNT,
(select SUM(AMOUNT)
FROM travel_reimbursements_items
WHERE type = 'HOTEL'
AND travel_request_no = B.travel_request_no
AND STATUS='APPROVED') as HOTEL_AMOUNT,
NVL((select SUM(AMOUNT)
FROM travel_reimbursements_items
WHERE type = 'CAR'
AND travel_request_no = B.travel_request_no
AND STATUS='APPROVED'),0)
+NVL((select SUM(AMOUNT)
FROM travel_reimbursements_items
WHERE type = 'HOTEL'
AND travel_request_no = B.travel_request_no
AND STATUS='APPROVED'),0) as TOTAL
FROM TRAVEL_REQUEST_ITEM A
LEFT OUTER JOIN TRAVEL_REQUEST B
ON (B.TRAVEL_REQUEST_NO= A.TRAVEL_REQUEST_SR_NO)

select b.employee_id
, sum(case when c.type = 'CAR' then c.amount end) car_amount
, sum(case when c.type = 'HOTEL' then c.amount end) hotel_amount
, sum(c.amount) total
from travel_request_item a
left outer join travel_request b
on (b.travel_request_no= a.travel_request_sr_no)
left outer join travel_reimbursements_items c
on ( c.travel_request_no = b.travel_request_no
and c.type in ('CAR','HOTEL')
and c.status = 'APPROVED'
)
group by b.employee_id
Regards,
Rob.

This should work in oracle.
SELECT B.EMPLOYEE_ID,
SUM(CASE WHEN C.type = 'CAR' and C.STATUS='APPROVED' THEN C.AMOUNT ELSE 0 END) as CAR_AMOUNT,
SUM(CASE WHEN C.type = 'HOTEL' and C.STATUS='APPROVED' THEN C.AMOUNT ELSE 0 END) as HOTEL_AMOUNT,
SUM(CASE WHEN C.type IN ('CAR', 'HOTEL') and C.STATUS='APPROVED' THEN C.AMOUNT ELSE 0 END) as TOTAL
FROM TRAVEL_REQUEST_ITEM A
LEFT OUTER JOIN TRAVEL_REQUEST B ON (B.TRAVEL_REQUEST_NO= A.TRAVEL_REQUEST_SR_NO)
LEFT OUTER JOIN TRAVEL_REIMBURSEMENTS_ITEMS C ON (C.TRAVEL_REQUEST_NO = A.TRAVEL_REQUEST_SR_NO)
GROUP BY B.EMPLOYEE_ID
Just do a conditional sum based on the item type.

Related

Incorrect results using parameter in SSRS

I have an SSRS report for which I created two datasets for. One for the actual report and one for the parameter.
Dataset 1 is the report
Dataset 2 simply pulls the parameter that I want to report on from the table where it is stored.
When I run the report and select the parameter, it shows me all the values, but when I select one, I still get every record rather than just the records based on the parameter.
Dataset 1
SELECT stk.ItemCode AS ItemCode, stk.warehouse AS warehouse,
stk.Description AS Description, stk.Assortment AS Assortment,
Items.Class_02, stk.ItemGroup AS ItemGroup, stk.ItemStatus AS ItemStatus,
stk.ItemUnit AS ItemUnit, ISNULL((SELECT TOP 1 dbo.bacoSalesPrice(p.ID,
0) FROM staffl p WHERE ({d '2019-05-27'} BETWEEN validfrom AND
ISNULL(validto,{d '9999-12-31'}))
AND prijslijst = 'SALESPRICE' AND Items.ItemCode = artcode ORDER BY
artcode, validfrom desc),0) AS SalesPackagePrice,
ROUND((stk.Stock/stk.SalesPkg),2) AS Stock, ROUND((stk.Stock +
stk.QtyToBeReceived - stk.QtyToBeDelivered)/stk.SalesPkg,2) AS
AvailableStock, stk.SearchCode AS SearchCode FROM Items INNER JOIN (
SELECT
v.magcode AS warehouse,
MAX(i.itemcode) AS ItemCode,
MAX(i.description_0) AS Description,
i.SearchCode AS SearchCode,
MAX(ia.Assortment) AS Assortment,
MAX(ia.Description_0) AS ItemGroup,
MAX(CASE
WHEN i.condition = 'A' THEN 'Active'
WHEN i.condition = 'B' THEN 'Blocked'
WHEN i.condition = 'D' THEN 'Discontinued'
WHEN i.condition = 'E' THEN 'Inactive'
WHEN i.condition = 'F' THEN 'Future'
END) AS ItemStatus,
ISNULL(MAX(a.purchasepackage), '-') AS ItemUnit,
MAX(i.SalesPackagePrice) AS SalesPackagePrice,
MAX(v.bestniv) AS Minimum,
MAX(v.maxvrd) AS Maximum,
MAX(i.lev_crdnr) AS Supplier,
MAX(a.DeliveryTimeInDays) AS DeliveryTime,
MAX(ISNULL(a.SlsPkgsPerPurPkg,1)) AS SalesPkg,
ISNULL(Actual.Quantity,0) AS Stock
,ISNULL(SUM(QtyToReceived),0) AS QtyToBeReceived
,ISNULL(SUM(QtyToBeDelivered),0) AS QtyToBeDelivered
FROM items i
JOIN voorrd v ON i.itemcode=v.artcode
LEFT JOIN itemaccounts a ON i.itemcode=a.itemcode and i.lev_crdnr=a.crdnr
AND i.itemcode IS NOT NULL AND a.itemcode IS NOT NULL AND i.lev_crdnr IS N
NOT NULL AND a.crdnr IS NOT NULL
JOIN ItemAssortment ia ON ia.Assortment = i.Assortment
LEFT OUTER JOIN
dbo.TempToBeReceivedDelivered#3E5BBBE6#FB7B#4309#9CE1#560885B9BF94# budget
ON v.magcode = budget.warehouse AND i.ItemCode = budget.artcode
AND v.magcode IS NOT NULL AND budget.warehouse IS NOT NULL AND i.ItemCode IS NOT NULL AND budget.artcode IS NOT NULL
LEFT OUTER JOIN
(SELECT GX.artcode, GX.warehouse,
GX.Quantity,
GX.AmtActualStock, GX.TotalCnt,
CASE WHEN GX.FreeQuantity > GX.CurrentQuantity THEN (CASE WHEN GX.CurrentQuantity < 0 THEN 0 ELSE GX.CurrentQuantity END) ELSE
(CASE WHEN GX.FreeQuantity < 0 THEN 0 ELSE GX.FreeQuantity END) END As FreeQuantity
FROM (
SELECT sb.ItemCode AS artcode, SUM(CASE WHEN sb.Date <= {d '2019-05-27'} THEN sb.Quantity END) as Quantity,
ROUND(SUM(CASE WHEN sb.Date <= {d '2019-05-27'} THEN sb.StockAmount END),2) as AmtActualStock,
SUM(CASE WHEN sb.Date <= {d '2019-05-27'} THEN sb.Quantity END) as CurrentQuantity,
SUM(CASE WHEN sb.Date <= {d '2019-05-27'} THEN sb.FreeStock END) AS FreeQuantity, sb.Warehouse,
SUM(sb.GbkmutCount) AS TotalCnt
FROM StockBalances sb WITH (NOLOCK) JOIN Items ON sb.ItemCode = Items.ItemCode JOIN ItemAssortment ON Items.Assortment = ItemAssortment.Assortment
--WHERE Items.Class_02 in #Customer
GROUP BY sb.ItemCode, sb.WareHouse, Items.Class_02
HAVING SUM(sb.GbkmutCount) > 0) GX) AS Actual
ON Actual.artcode = i.ItemCode AND Actual.warehouse = v.magcode AND Actual.artcode IS NOT NULL AND i.ItemCode IS NOT NULL AND Actual.warehouse IS NOT NULL AND v.magcode IS NOT NULL
WHERE i.type IN ('S', 'B')
AND i.ItemCode BETWEEN '0030122186' AND 'XS45000'
AND i.Condition IN ('A')
AND ((i.IsSalesItem <> 0)) AND i.Type IN ('S', 'B')
AND 1=1
GROUP BY v.magcode , i.itemcode, i.SearchCode, Actual.Quantity
) stk ON items.ItemCode = stk.ItemCode
INNER JOIN grtbk ON Items.GLAccountDistribution = grtbk.reknr
ORDER BY stk.ItemCode
Dataset 2
SELECT Class_02, ItemCode FROM Items
Parameter in SSRS is set to Get values from Query, Value field: Class_02
Label field: Class_02

query won't work after pivot

I'm trying to develop a query and i got something like this
SELECT a.No,
a.Finish,
a.Shift,
a.McCode,
d.NAME,
b.ItemCode,
b.ItemName,
b.Qty,
b.LotNo,
b.Description,
CASE
WHEN b.Description LIKE '%not good%' THEN 'NG'
ELSE 'OK'
END AS OKNG,
c.ItemCode AS matcode,
c.LotNo AS matlot,
CASE
WHEN e.GroupName = 'CONTACT' THEN 'CONTACT'
ELSE 'Coil/Silver/Wire'
END AS GroupName,
( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty AS materialused
FROM PPRDDLV a
LEFT JOIN ICMUTTRAN b
ON a.PrdNo = b.TranNo
AND a.No = b.TranId
LEFT JOIN ICMUTTRAN c
ON a.PrdNo = c.TranNo
AND a.Finish = c.DatePost
AND c.TranTypeID = 6
AND c.LotNo <> '0'
LEFT JOIN popr d
ON a.OprCode = d.Code
LEFT JOIN ICITEM e
ON c.ItemId = e.id
WHERE c.qty IS NOT NULL
AND b.ItemCode IS NOT NULL
I got around 49000 records in around 2 seconds, then I wan't to pivot a column that has 2 kind of value, so I turned it to something like this
SELECT no,
finish,
shift,
mccode,
NAME,
itemcode,
itemname,
qty,
lotno,
description,
okng,
matcode,
matlot
FROM (SELECT a.No,
a.Finish,
a.Shift,
a.McCode,
d.NAME,
b.ItemCode,
b.ItemName,
b.Qty,
b.LotNo,
b.Description,
CASE
WHEN b.Description LIKE '%not good%' THEN 'NG'
ELSE 'OK'
END AS OKNG,
c.ItemCode AS matcode,
c.LotNo AS matlot,
CASE
WHEN e.GroupName = 'CONTACT' THEN 'CONTACT'
ELSE 'Coil/Silver/Wire'
END AS GroupName,
( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty AS materialused
FROM PPRDDLV a
LEFT JOIN ICMUTTRAN b
ON a.PrdNo = b.TranNo
AND a.No = b.TranId
LEFT JOIN ICMUTTRAN c
ON a.PrdNo = c.TranNo
AND a.Finish = c.DatePost
AND c.TranTypeID = 6
AND c.LotNo <> '0'
LEFT JOIN popr d
ON a.OprCode = d.Code
LEFT JOIN ICITEM e
ON c.ItemId = e.id
WHERE c.qty IS NOT NULL
AND b.ItemCode IS NOT NULL) AS a
PIVOT (Max(materialused)
FOR groupname IN ([CONTACT],
[Coil/Silver/Wire])) AS b
but the query won't complete even after 10 minutes, it won't even show a single records. beside that one, the first query before I used pivot, I put an order by a.no but when I executed it, the result only shows to record 105 but the query is still working and no more record was loaded.
can anyone help me find out what's going on?
thank you!
Here's the sample data collected from the inner query and the expected value after the query.
enter image description here
I realize that I selected "matcode" in the outer select while it shouldn't be there (still didn't work though, and note for the column "material used", I'll be using it later after the pivot is done)
Try using conditional aggregate instead of pivot.
SELECT no,
finish,
shift,
mccode,
NAME,
itemcode,
itemname,
qty,
lotno,
description,
okng,
matcode,
matlot,
[CONTACT] = Max(CASE WHEN GroupName = 'CONTACT' THEN materialused END),
[Coil/Silver/Wire] = Max(CASE WHEN GroupName <> 'CONTACT' THEN materialused END)
FROM (<inner query>) AS a
GROUP BY no,
finish,
shift,
mccode,
NAME,
itemcode,
itemname,
qty,
lotno,
description,
okng,
matcode,
matlot
---IF you don't have index on filter columns then try to apply for performance
SELECT a.No,
a.Finish,
a.Shift,
a.McCode,
d.NAME,
b.ItemCode,
b.ItemName,
b.Qty,
b.LotNo,
b.Description,
CASE WHEN b.Description LIKE '%not good%' THEN 'NG'
ELSE 'OK'
END AS OKNG,
c.ItemCode,
c.LotNo,
MAX(CASE WHEN e.groupname ='CONTACT' THEN ( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty END)OVER(ORDER BY a.no) AS [CONTACT],
MAX(CASE WHEN e.groupname ='Coil/Silver/Wire' THEN ( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty END)OVER(ORDER BY a.no) AS [Coil/Silver/Wire]
FROM PPRDDLV a WITH(NOLOCK)
LEFT JOIN ICMUTTRAN b WITH(NOLOCK)
ON a.PrdNo = b.TranNo
AND a.No = b.TranId
LEFT JOIN ICMUTTRAN c WITH(NOLOCK)
ON a.PrdNo = c.TranNo
AND a.Finish = c.DatePost
AND c.TranTypeID = 6
AND c.LotNo <> '0'
LEFT JOIN popr d WITH(NOLOCK)
ON a.OprCode = d.Code
LEFT JOIN ICITEM e
ON c.ItemId = e.id
WHERE c.qty IS NOT NULL
AND b.ItemCode IS NOT NULL

Complex Case Statement Issue - Oracle SQL

Wrote the query below, but am getting multiplied amounts because the aggregation needs to occur before the case statements. Would love some advice on the best way to structure this.
Select Store, CUSTID, CUST.ID_CUST,
Sum(
CASE
WHEN Cust_Gift.Code_Status = 'C' AND Gift_Item.FLAG_STORE_LOC = 'N'
THEN Cust_Gift.AMT_PAID ELSE 0
END) GiftAmt,
Sum(
CASE WHEN Cust_Gift.Code_Status = 'C' AND Gift_Item.FLAG_STORE_LOC = 'Y'
THEN Cust_Gift.AMT ELSE 0
END) CustGiftAmt,
Sum(
CASE WHEN Cust_Coupon.Code_Status = 'C'
THEN Cust_Coupon.AMT
ELSE 0
END) CouponAmt,
Sum(CASE WHEN Cust_Sports.Status = 'C'
THEN Cust_Sports.AMT
ELSE 0
END) SportsAmt
FROM CUST
LEFT OUTER JOIN CUST_GIFT
ON CUST.ID_CUST = CUST_GIFT.ID_CUST
LEFT OUTER JOIN CUST_COUPON
ON CUST.ID_CUST = CUST_COUPON.ID_CUST
LEFT OUTER JOIN CUST_SPORTS
ON CUST.ID_CUST = CUST_SPORTS.ID_CUST
INNER JOIN GIFT_ITEM
ON CUST_GIFT.ID_GIFT_ITEM = GIFT_ITEM.ID_GIFT_ITEM
WHERE (STORE = 'M669098' OR STORE = 'M66923434' )
Group by CustID, Store, CUST.ID_CUST
This is one way you could do it:
SELECT cust.store,
cust.custid,
cust.id_cust,
gift.giftamt,
gift.custgift,
cpn.couponamt,
sprt.sportsamt
FROM cust
LEFT OUTER JOIN (SELECT id_cust,
SUM(CASE WHEN cg.code_status = 'C' AND gi.flag_store_loc = 'N' THEN cg.amt_paid END) giftamt,
SUM(CASE WHEN cg.code_status = 'C' AND gi.flag_store_loc = 'Y' THEN cg.amt_paid END) custgiftamt
FROM cust_gift cg
INNER JOIN gift_item gi ON cg.id_gift_item = gi.id_gift_item) gift ON cust.id_cust = gift.id_cust
LEFT OUTER JOIN (SELECT id_cust,
SUM(CASE WHEN code_status = 'C' THEN amt END) couponamt
FROM cust_coupon) cpn ON cust.id_cust = cpn.id_cust
LEFT OUTER JOIN (SELECT id_cust,
SUM(CASE WHEN status = 'C' THEN amt END) sportsamt
FROM cust_sports) sprt ON cust.id_cust = sprt.id_cust
WHERE (STORE = 'M669098' OR STORE = 'M66923434');

How to convert two rows value in a single row?

I have below sql server query data
Looking for solution.
SQL Query:
SELECT
p.ProjectName,
i.ItemName,
inv.TransactionDirection,
SUM(inv.TransactionQty) AS TransactionQuantity
FROM INVTransaction inv
JOIN BDProject p ON p.ProjectID=inv.ProjectID
JOIN MDItem i ON i.ItemID=inv.ItemID
GROUP BY p.ProjectName,
i.ItemName,
inv.TransactionDirection
I think you just want conditional aggregation:
SELECT p.ProjectName, i.ItemName,
SUM(CASE WHEN inv.TransactionDirection = 'IN' THEN inv.TransactionQty ELSE 0 END) as IN_Quantity,
SUM(CASE WHEN inv.TransactionDirection = 'OUT' THEN inv.TransactionQty ELSE 0 END) as OUT_Quantity,
SUM(CASE WHEN inv.TransactionDirection = 'IN' THEN inv.TransactionQty
WHEN inv.TransactionDirection = 'OUT' THEN -inv.TransactionQty
ELSE 0
END) as Balance
FROM INVTransaction inv JOIN
BDProject p
ON p.ProjectID = inv.ProjectID JOIN
MDItem i ON i.ItemID = inv.ItemID
GROUP BY p.ProjectName, i.ItemName
You can use Pivot for this. Below is working query.
SELECT PROJECTNAME,ITEMNAME,[IN],[OUT] ,ISNULL([IN],0)-ISNULL([OUT],0) AS BALANCE FROM
(SELECT PROJECTNAME,ITEMNAME,TRANSACTIONDIRECTION,TRANSACTIONQUANTITY FROM TRANSACTIONS
)A
PIVOT (SUM(TRANSACTIONQUANTITY) FOR TRANSACTIONDIRECTION IN ([IN],[OUT])) AS PVT
Replace TRANSACTIONS with your table name
As #Gordon Linoff almost provided solution but for balance column you can replace
SUM(inv.TransactionQty) as Balance
With
SUM(CASE WHEN inv.TransactionDirection = 'IN'
THEN inv.TransactionQty
ELSE -1*inv.TransactionQty END) as Balance

: Select query with sum() as subquery

I have a query that I need to add a column to. I can find many similar examples but nothing quite works right for this situation. There could be infinite CategoryIDs and I need to add the Sum(IsOutage) grouped by CategoryID. This is some sample data:
and here is the closest I have to getting it to work:
SELECT c.CategoryID
, c.Name
, COUNT(i.IssueID) AS TotalIssues
, AVG(DATEDIFF(MI, i.StartDate, i.ResolvedDate)) AS AvgDuration
,(Select COUNT(h.IssueID) From dbo.hdIssues AS h Where h.CategoryID = i.CategoryID AND IsOutage = 1 ) AS TotalOutages
FROM dbo.hdCategories AS c INNER JOIN
dbo.hdIssues AS i ON c.CategoryID = i.CategoryID
WHERE (i.StatusID = 3)
GROUP BY c.CategoryID, c.Name, TotalOutages
Am I close? Please advise and thanx in advance
EDIT: This is a mock up of what the result should look like:
If i correctly understand your needs this query should give you desired result:
SELECT x.* ,
y.SumIsOutage
FROM (SELECT c.CategoryID ,
c.Name ,
COUNT(i.IssueID) AS TotalIssues ,
AVG(DATEDIFF(MI, i.StartDate, i.ResolvedDate)) AS AvgDuration
FROM dbo.hdCategories AS c
INNER JOIN dbo.hdIssues AS i ON c.CategoryID = i.CategoryID
WHERE (i.StatusID = 3)
GROUP BY c.CategoryID, c.Name ) x
LEFT JOIN (SELECT DISTINCT i.CategoryId,
SUM(CONVERT(INT,i.isOutage)) OVER (PARTITION BY i.CategoryId) AS SumIsOutage
FROM dbo.hdIssues AS i ) y
ON x.CategoryId = y.CategoryId
You can use conditional aggregation. Also, you shouldn't group by totaloutages
SELECT
c.CategoryID
, c.Name
, COUNT(i.IssueID) AS TotalIssues
, AVG(DATEDIFF(MI, i.StartDate, i.ResolvedDate)) AS AvgDuration
,sum(case when IsOutage = 1 then 1 else 0 end) AS TotalOutages
FROM dbo.hdCategories AS c INNER JOIN
dbo.hdIssues AS i ON c.CategoryID = i.CategoryID
WHERE i.StatusID = 3
GROUP BY c.CategoryID, c.Name
You don't need another subquery for this count. Just count the rows that you're interested in:
COUNT(CASE WHEN i.IsOutage = 1 THEN 1 END)
In the context of your query:
SELECT
c.CategoryID
, c.Name
, COUNT(i.IssueID) AS TotalIssues
, AVG(DATEDIFF(MI, i.StartDate, i.ResolvedDate)) AS AvgDuration
, COUNT(CASE WHEN CONVERT(INT, i.IsOutage) = 1 THEN 1 END) AS TotalOutages
FROM
dbo.hdCategories AS c
INNER JOIN
dbo.hdIssues AS i
ON c.CategoryID = i.CategoryID
WHERE
i.StatusID = 3
GROUP BY
c.CategoryID
, c.Name