Group By by hiding a column - TSQL - sql

I have a table structure
Table1
ID Hours Qty ProductID
1 2 1 100
1 3 5 200
2 6 6 100
2 2 2 200
If productid is (1,2,3) then i need sum ( Qty * Hours),If productid in (200,300,400,500) then i need sum(qty).
I have written a code like this
select ID,case when productid in (1,2,3) then
SUM( qty * hrs)
when productid in (100,200,300) then SUM( qty ) end result1
from Prod group by id ,productid
but i don't want to group by productid,i would like to pass it in "IN clause".How to achieve it.

Move the SUM() outside of the CASE WHEN statement.
SELECT
ID,
SUM(case when productid in (1,2,3) then qty * hrs
when productid in (100,200,300) then qty
end) result1
FROM
Prod
GROUP BY
ID

Assuming you want all columns plus the result of your query, you can do this:
select p.*, aux.result
from Prod p
inner join (select ID,case when productid in (1,2,3) then SUM( qty * hrs)
when productid in (100,200,300) then SUM( qty )
end as result
from Prod group by id ,productid) aux on aux.id = p.id

Related

How to filter inconsistent records in sqlite

Say I have SQLite table with the following records:
recID
productID
productName
1
1
Product A
2
2
Product B
3
2
Product C
4
3
Product D
5
3
Product D
recID = primary key, auto increment.
If I run:
SELECT productID, productName
FROM table
GROUP BY productID, productName
Result is:
productID
productName
1
Product A
2
Product B
2
Product C
3
Product D
As you can see, productID 2 has inconsistent productName: Product B and Product C. How do I run query just to detect the inconsistent ones? Eg I want the result to be:
productID
productName
2
Product B
2
Product C
Use EXISTS to get a productID with more than 1 productNames:
SELECT t1.productID, t1.productName
FROM tablename t1
WHERE EXISTS (
SELECT *
FROM tablename t2
WHERE t2.productID = t1.productID AND t2.productName <> t1.productName
);
Or, for a small dataset use aggregation in a subquery which counts the distinct number of productNames of each productID, with the operator IN:
SELECT productID, productName
FROM tablename
WHERE productID IN (
SELECT productID
FROM tablename
GROUP BY productID
HAVING COUNT(DISTINCT productName) > 1
);

SQL sum grouped by field with all rows

I have this table:
id sale_id price
-------------------
1 1 100
2 1 200
3 2 50
4 3 50
I want this result:
id sale_id price sum(price by sale_id)
------------------------------------------
1 1 100 300
2 1 200 300
3 2 50 50
4 3 50 50
I tried this:
SELECT id, sale_id, price,
(SELECT sum(price) FROM sale_lines GROUP BY sale_id)
FROM sale_lines
But get the error that subquery returns different number of rows.
How can I do it?
I want all the rows of sale_lines table selecting all fields and adding the sum(price) grouped by sale_id.
You can use window function :
sum(price) over (partition by sale_id) as sum
If you want sub-query then you need to correlate them :
SELECT sl.id, sl.sale_id, sl.price,
(SELECT sum(sll.price)
FROM sale_lines sll
WHERE sl.sale_id = sll.sale_id
)
FROM sale_lines sl;
Don't use GROUP BY in the sub-query, make it a co-related sub-query:
SELECT sl1.id, sl1.sale_id, sl1.price,
(SELECT sum(sl2.price) FROM sale_lines sl2 where sl2.sale_id = sl.sale_id) as total
FROM sale_lines sl1
In addition to other approaches, You can use CROSS APPLY and get the sum.
SELECT id, sale_id,price, Price_Sum
FROM YourTable AS ot
CROSS APPLY
(SELECT SUM(price) AS Price_Sum
FROM YourTable
WHERE sale_id = ot.sale_id);
SELECT t1.*,
total_price
FROM `sale_lines` AS t1
JOIN(SELECT Sum(price) AS total_price,
sale_id
FROM sale_lines
GROUP BY sale_id) AS t2
ON t1.sale_id = t2.sale_id

How can I merge a result set from a matrix table?

Say I have a price matrix that looks like this:
ID SalePrice CostPrice
1 200 0
1 0 75
1 0 100
2 150 0
2 0 50
2 500 0
I then have a table with 75k ID´s that I wish to join with the price matrix and return one row per ID with the lowest value for SalePrice and CostPrice. Like so:
ID SalePrice CostPrice
200 75
150 50
Here is the sql I currently use:
declare #priceMatrix TABLE(
prodNo varchar(50) NOT NULL,
salePrice decimal,
costPrice decimal)
INSERT INTO #priceMatrix
SELECT pm.ID, pm.SalePr, pm.CstPr
FROM PriceMatrix pm
GROUP BY pm.ID, pm.SalePrice, pm.CostPrice
ORDER BY pm.ID ASC
SELECT ProductTable.ProdNo,
(SELECT TOP 1 salePrice FROM #priceMatrix WHERE ProductTable.ID = ID AND
costPrice = 0 ORDER BY salePrice ASC) AS SalePrice ,
(SELECT TOP 1 costPrice FROM #priceMatrix WHERE ProductTable.ID = ID AND
salePrice = 0 ORDER BY costPrice ASC) AS CostPrice ,
FROM ProductTable
GROUP BY ProductTable.ID
But with 75000 ID´s the performance is just terrible using sub queries. Not to say completely useless.
Is there an effective way to achieve what I´m looking for?
SELECT ProductTable.ProdNo,
sub1.MIN_SALE_PRICE as SalePrice ,
sub2.MIN_COST_PRICE as CostPrice
FROM ProductTable pt
LEFT JOIN (SELECT MIN(salePrice) MIN_SALE_PRICE, ID
FROM #priceMatrix
WHERE costPrice = 0
GROUP BY ID) sub1 ON pt.ID=sub1.ID
LEFT JOIN (SELECT MIN(costPrice ) MIN_COST_PRICE, ID
WHERE salePrice = 0
FROM #priceMatrix
GROUP BY ID) sub2 ON pt.ID=sub2.ID
GROUP BY ProductTable.ID
Move the sub selects with ORDER BY to JOINS to evaluate them once for all products
This actually turned out to execute faster by 1 sek:
SELECT ProductTable.ProdNo,
(SELECT MIN(salePrice)
FROM PriceMatrix
WHERE PriceMatrix.ID = ProductTable.ID
AND PriceMatrix.CostPrice = 0
AND PriceMatrix.SalePrice > 0) AS SalePrice,
(SELECT MIN(costPrice)
FROM PriceMatrix
WHERE PriceMatrix.ID = ProductTable.ID
AND PriceMatrix.CostPrice > 0
AND PriceMatrix.SalePrice = 0) AS CostPrice
FROM ProductTable

How to exclude rows from sum but still show them?

I have a table itemsInShippment with the following data:
itemid shippmentid qty
10 1 100
20 1 200
10 2 300
10 3 1000
and table shippments
shippmentid date shippmentstatus supplierid
1 2015-01-12 OK 5000
2 2015-01-17 OK 5000
3 2015-01-17 Cancelled 5000
I need to write a query that shows this details about specific shippment say shipmentid 1. My given parameters are supplierid and date. together they related to one shipment (unique).
For supplierid=5000 and date=2015-01-12 I want to get:
itemid qty qtyInOtherShipments
10 100 300 //1000 is canceled.
20 200 0
My query works fine without considering the cancelled:
SELECT cte.*
FROM
(SELECT
a.itemid, b.date, a.qty,
(coalesce( SUM(a.qty) OVER (PARTITION BY a.itemid), 0) -
coalesce( SUM(a.qty) OVER (PARTITION BY a.itemid, a.shipmentid) ,0) ) AS qtyInOtherShipments,
FROM
itemsInShippment a
LEFT JOIN
shippments b using (shippmentid)
WHERE
b.supplierid = 5000) AS cte
WHERE
cte.date = '2015-01-12'
the cte must be this way as in qtyInOtherShipments I Sum the total qty and then remove my own qty. In order to sum the total qty I can't do WHERE d.date=... inside I must do that outside.
This query gives:
itemid qty qtyInOtherShipments
10 100 1300
20 200 0
I'm having trouble taking under consideration the cancelled shipments.
if I change the Where to :
where b.supplierid = 5000 and b.shippmentstatus not like 'cancelled'
it works... I will see:
itemid qty qtyInOtherShipments
10 100 300
20 200 0
but if I run the query on cancelled shipments (supplierid=5000 and date=2015-01-17) I will get:
itemid qty qtyInOtherShipments
nothing
what I should have get is:
itemid qty qtyInOtherShipments
10 1000 300
so my problem is that I don't want to sum itemid that is related to cancelled but I still want to see this rows.
How do I get the correct result?
You want to exclude canceled items only from sums. So, do not filter them with where, just filter them on sums:
SUM(case when b.shippmentstatus <> 'cancelled' then a.qty end) OVER (PARTITION BY ...
Sum does not take in consideration null, that's why the above works. (When status is canceled the case expression will return null.)
A more efficient variant of Florian's answer exists for PostgreSQL 9.4, the filter clause for an aggregate.
SUM (a.qty) FILTER (WHERE b.shippmentstatus <> 'cancelled') OVER (PARTITION BY ...
See FILTER in the docs for aggregates. It's basically a mini-WHERE clause that applies only for that aggregate.
Thanks to #a_horse_with_no_name for pointing it out earlier.
Try Below query
create table #itemsInShippment (itemid int, shippmentid int, qty int)
insert into #itemsInShippment (itemid, shippmentid, qty)
SELECT 10 as itemid, 1 as shippmentid, 100 as qty UNION
SELECT 20 , 1, 200 UNION
SELECT 10 , 2, 300 UNION
SELECT 10 , 3, 1000
CREATE TABLE #shippments (shippmentid int , dt date, shippmentstatus varchar(50), supplierid int)
insert into #shippments (shippmentid, dt, shippmentstatus,supplierid)
SELECT 1 as shippmentid, '2015-01-12' as dt, 'OK' as shippmentstatus , 5000 as supplierid UNION ALL
SELECT 2, '2015-01-17', 'OK' , 5000 UNION ALL
SELECt 3, '2015-01-17' , 'Cancelled' , 5000
SELECT cte.*
FROM (
select a.itemid,b.dt,a.qty,
(coalesce( SUM(case when shippmentstatus <> 'Cancelled' then a.qty else 0 end) OVER (PARTITION BY a.itemid) ,0) -
coalesce( SUM(case when shippmentstatus <> 'Cancelled' then a.qty else 0 end) OVER (PARTITION BY a.itemid,a.shippmentid) ,0) )
AS qtyInOtherShipments
from #itemsInShippment a
left join #shippments b on a.shippmentid = b.shippmentid
where b.supplierid = 5000 --and shippmentstatus = 'Cancelled'
) as cte
where cte.dt='2015-01-12'

SQL Server 2005 query, update qtys to 0 where orderid <> min(orderid)

I have a table
OrderID Qty ShopID
-----------------------
1 50 10
1 50 11
2 10 15
2 10 18
The person ordered the same order at different shops (they will later decide which one will supply it), but I must only show one qty per order, please help setting the qty = 0 where the orderid is the same and shopid > min(shopID)
e.g.
OrderID Qty ShopID
-----------------------
1 50 10
1 0 11
2 10 15
2 0 18
This is just an example of the real world problem pls
You can try something like this:
;WITH CTE AS
(
SELECT
OrderID, Qty, ShopID,
RowNum = ROW_NUMBER() OVER (PARTITION BY OrderID ORDER BY ShopID DESC)
FROM
dbo.YourOrderTableHere
)
SELECT
OrderID,
OrderedQty = CASE RowNum
WHEN 1 THEN Qty ELSE 0
END,
ShopID
FROM CTE
Basically, I "partition" the data by OrderID - so each row within a given order gets assigned a consecutive RowNum.
In the select from the CTE (Common Table Expression), I return the quantity as stored in the table for the order with RowNum = 1, and I suppress that quantity and return 0 instead for all additional rows for that same OrderID.
This gives me an output of: