SQL Server query question (Count maybe?) - sql

I have the following query:
SELECT A.shipment_id
,B.box_id
,A.shipment_status
FROM shipments A
join boxes B on A.shipment_id = B.shipment_id
where A.shipment_status = 2
Group by B.box_id, A.shipment_id, A.shipment_status
That returns a result set that looks like this:
shipment_id, box_id, shipment_status
101, boxA, 2
101, boxB, 2
101, boxC, 2
102, box101, 2
102, box102, 2
103, boxA1, 2
103, boxA2, 2
I would like to return something like this instead (showing a total amount of boxes per shipment):
shipment_id, box count, shipment_status
101, 3, 2
102, 2, 2
103, 2, 2
How would I achieve this?
Thanks!

SELECT A.shipment_id
,COUNT(*) AS boxcount
,A.shipment_status
FROM shipments A
join boxes B on A.shipment_id = B.shipment_id
where A.shipment_status = 2
Group by A.shipment_id, A.shipment_status
Just need to remove the box_id from the GROUP BY and use COUNT, as you said in your title.

Try this:
SELECT A.shipment_id
, count(1)
, A.shipment_status
FROM shipments A
join boxes B on A.shipment_id = B.shipment_id
where A.shipment_status = 2
Group by A.shipment_id, A.shipment_status

Related

Count Childs and partition by GrandParent, that resides in an unpivoted hierarchy

I want to show the COUNT on every row how many BuildingID's there are within the MainGroundID's, while having to deal with a parent-child hierarchy that is unpivoted.
Unfortunately there is no logic within the way the GroundID and MainGroundID's are written (although it looks that way in my example, since I made an example dataset).
PMEBuilding
BuildingID, GroundID
1, 100
2, 100
3, 101
4, 201
5, 201
6, 201
7, 202
In reality the above table has 34K rows and 80+ fields.
The GroundID from the table above is N:1 to the table below via GroundID.
Within the PMEGroudn table Some GroundID's refer to a certain MainGroundID, which in turn also refer to Parents higher up in the hierarchy. The 'GrandParents' are those that have a NULL value as GroundID.
PMEGround
GroundID, MainGroundID
1, NULL --GrandParent
10, 1
100, 10
101, 10
2, NULL --GrandParent
20, 2
201, 20
202, 20
In reality the above table has 2K rows of which around 500 'GrandParents'.
I want this to be the end result:
MainGroundID MainGroundBuildingCount
1, 3
2, 7
The following code is what I used so far, but it doesn't work entirely yet:
;WITH UNPIVOT_HIERARCHY AS (
SELECT GROUNDID
,MAINGROUNDID
,PathID = CAST(GROUNDID AS VARCHAR(MAX))
FROM PMEGROUND
WHERE NULLIF(MainGroundID, '') IS NULL
UNION All
SELECT GROUNDID = r.GROUNDID
,MAINGROUNDID = r.MAINGROUNDID
,PathID = p.PathID+CONCAT(',',CAST(r.GROUNDID AS VARCHAR(MAX)))
FROM PMEGROUND r
JOIN UNPIVOT_HIERARCHY p ON r.MAINGROUNDID = p.GROUNDID
)
SELECT
B.Lvl3 AS 'MainGroundID' --This is the GrandParent, which works fine
,COUNT(PMEBUILDING.GROUNDID) OVER (PARTITION BY B.Lvl3) AS 'MainGroundCountBuildings'
FROM PMEGROUND
LEFT JOIN UNPIVOT_HIERARCHY
ON UNPIVOT_HIERARCHY.GROUNDID = PMEGROUND.GROUNDID
LEFT JOIN PMEBUILDING
ON PMEBUILDING.GROUNDID = PMEGROUND.GROUNDID
CROSS Apply (
SELECT Lvl1 = xDim.value('/x[3]','varchar(50)')
,Lvl2 = xDim.value('/x[2]','varchar(50)')
,Lvl3 = xDim.value('/x[1]','varchar(50)')
,Lvl4 = xDim.value('/x[4]','varchar(50)')
FROM ( VALUES (CAST('<x>' + REPLACE(PathID,',','</x><x>')+'</x>' AS xml))) B(xDim)
) B
GROUP BY B.Lvl3, PMEBUILDING.GROUNDID
Without the GROUP BY it gives duplicate MainGroundIDs, but the correct count.
With the GROUP BY it still gives duplicate MainGroundIDs but less, but the count is messed up now.
I want this to be the end result:
MainGroundID MainGroundBuildingCount
1, 3
2, 7
Don't you mean the end result should be?
MainGroundID MainGroundBuildingCount
1, 3
2, 4
Assuming, based on the given data, that there are 3 levels of hierarchy and PMEBuilding.GroundID contains only grandchildren I would use the following to achieve the end result:
select
gp.GroundID, count(distinct b.BuildingID)
from PMEGround gp
join PMEGround p on p.MainGroundID = gp.GRoundID
join PMEGround c on c.MainGroundID = p.GRoundID
join PMEBuilding b on b.GroundID = c.GroundID
where gp.MainGroundID is null
group by gp.GroundID
order by 1

How to query SQLite to find sum, latest record, grouped by id, in between dates?

Items (itemId, itemName)
Logs (logId, itemId, qtyAdded, qtyRemoved, availableStock, transactionDate)
Sample Data for Items:
itemId itemName
1 item 1
2 item 2
Sample Data for Logs:
logid itemId qtyAdded qtyRemoved avlStock transDateTime
1 2 5405 0 5405 June 1 (4PM)
2 2 1000 0 6405 June 2 (5PM)
3 2 0 6000 405 June 3 (11PM)
I need to see all items from Items table and their SUM(qtyAdded), SUM(qtyRemoved), latest availableStock (there's an option for choosing the range of transactionDate but default gets all records). Order of date in final result does not matter.
Preferred result: (without date range)
itemName qtyAddedSum qtyRemovedSum avlStock
item 1 6405 6000 405
item 2 <nothing here yet>
With date Range between June 2 (8AM) and June 3 (11:01PM)
itemName qtyAddedSum qtyRemovedSum avlStock
item 1 1000 6000 405
item 2 <no transaction yet>
So as you can see, final result is grouped which makes almost all my previous query correct except my availableStock is always wrong. If I focus in the availableStock, I can't get the two sums.
you could use group by sum, and between
select itemName, sum(qtyAdded), sum(qtyRemoved), sum(avlStock)
from Items
left join Logs on logs.itemId = items.itemId
where transDateTime between '2017-06-02 08:00:00' and '2017-06-03 23:00:00'
group by itemId
or
If you need the last avlStock
select itemName, sum(qtyAdded), sum(qtyRemoved), tt.avlStock
from Items
left join Logs on logs.itemId = items.itemId
INNER JOIN (
select logid,avlStock
from logs
inner join (
select itemId, max(transDateTime) max_trans
from Logs
group by itemId
) t1 on logs.itemId = t1.ItemId and logs.transDateTime = t1.max_trans
) tt on tt.logId = Logs.itemId
where transDateTime between '2017-06-02 08:00:00' and '2017-06-03 23:00:00'
group by itemId
Okay, I tried both of these and they worked, can anyone confirm if these are already efficient or if there are some more efficient answers there.
SELECT * FROM Items LEFT JOIN
(
SELECT * FROM Logs LEFT JOIN
(
SELECT SUM(qtyAdd) AS QtyAdded, SUM(qtySub) AS QtyRemoved, availableStock AS Stock
FROM Logs WHERE transactionDate BETWEEN julianday('2017-07-18 21:10:40')
AND julianday('2017-07-18 21:12:00') GROUP BY itemId
)
ORDER BY transactionDate DESC
)
USING (itemId) GROUP BY itemName;
SELECT * FROM Items LEFT JOIN
(
SELECT * FROM Logs LEFT JOIN
(
SELECT SUM(qtyAdd) AS QtyAdded, SUM(qtySub) AS QtyRemoved, availableStock AS Stock
FROM Logs GROUP BY itemId
)
ORDER BY transactionDate DESC
)
USING (itemId) GROUP BY itemName;

sql Left join giving duplicate multiple values

Friends I am unable to fetch correct result Please suggest , Thanks in Advance .
I have two tables and trying to get balance quantity
One is Purchase Table (purchase_detail)
Pur_Date Item_Id Pur_Qty
2014-10-08 12792 25
2014-11-01 133263 20
2014-10-01 133263 2
2014-11-20 12792 10
Second is Sale Table (sale_detail)
Sale_Date Item_Id Sale_Qty
2014-11-17 133263 -6
2014-11-05 12792 -1
2014-11-24 133263 -2
2014-10-28 12792 -6
2014-11-05 133263 -2
After using left join
SQL :
select a.pur_item, sum(a.pur_qty + b.sold_qty ) as bal_qty
from purchase_item_qty_amount a left join sale_item_qty_amount b
on a.pur_item =b.sale_item where a.pur_item IN( 12792,133263)
group by 1;
Result - But it's incorrect
Item_Id Bal_qty
12792 56
133263 46
Result - It should be
Item_Id Bal_qty
12792 28
133263 12
Try this untested query:
select pur_item, sum(as bal_qty) from (
select pur_item, sum(a.pur_qty) as bal_qty
from purchase_item_qty_amount a
group by 1
union
select pur_item, sum(b.sold_qty)as bal_qty
from sale_item_qty_amount b
group by 1)
group by 1
You have to use union instead of join as the left rows have multiple matches to the right which cause too much data to be calculated. Try running your query without the sum and group by to see the raw data being calculated and you will see what I mean.
Your query with no group/sum:
select a.pur_item, a.pur_qty, b.sold_qty from purchase_item_qty_amount a left join sale_item_qty_amount b on a.pur_item = b.sale_item where a.pur_item IN (12792,133263);
Here is a query that works as you would expect:
select item, sum(a.pur_qty) + sum(a.sold_qty) as bal_qty from (select pur_item as item, sum(pur_qty) as pur_qty, 0 as sold_qty from purchase_item_qty_amount where pur_item in (12792,133263) group by pur_item union select sale_item as item, 0 as pur_qty, sum(sold_qty) as sold_qty from sale_item_qty_amount where sale_item in (12792,133263) group by sale_item) a group by item;
Here is the full dummy of your question,try this one you will get your desired result:-
purchase table
create table pt(Pur_Date date,Item_Id number, Pur_Qty number)
insert into pt values('08.oct.2014',12792,25);
insert into pt values('01.nov.2014',133263,20);
insert into pt values('01.oct.2014',133263,2);
insert into pt values('20.nov.2014',12792,10);
sales table
create table st(Sale_Date date , Item_Id number, Sale_Qty number)
insert into st values('17.nov.2014',133263,-6);
insert into st values('05.nov.2014',12792,-1);
insert into st values('24.nov.2014',133263,-2);
insert into st values('28.oct.2014',12792,-6);
insert into st values('05.nov.2014',133263,-2);
select purchase.Item_Id,(purchase.pur_qty+sale.sale_qty) bal_qty
from
(
select a.Item_Id, sum(a.pur_qty) pur_qty
from pt a
group by a.Item_Id
) purchase
left join
(
select b.Item_Id,
sum(b.sale_qty ) sale_qty
from st b
group by b.Item_Id
) sale
on sale.Item_Id = purchase.Item_Id
where purchase.Item_Id in (12792,133263)
order by 1;

SQL detect changes in log stored in database

I have db log of items prices. Sometimes ( usually every month ) new State with prices stored into db.
Each item has uniqueid. It doen't change from month to month.
I've build sample database:
http://sqlfiddle.com/#!6/0bc28/3
I need to detect item price changes. For example
If item1 price on 2013-01-01 was 122, on 2013-02-01 was 122, on 2013-03-01 was 124
Select should show 1 row
itemname = item1, oldPrice = 122, newPrice = 124, dateCHanged = 2013-03-01
This should work:
with x as (
select i.*, s.datecreated, row_number() over (partition by uniqueid order by datecreated) as rn
from items i
inner join states s on i.stateid = s.id
)
select x1.uniqueId, x1.price as oldPrice, x2.price as newPrice, x2.dateCreated as dateChanged
from x x1
inner join x x2 on x1.uniqueid = x2.uniqueid
--and datediff(month, x1.datecreated, x2.datecreated) = 1
and x1.rn - x2.rn = 1
and x1.price <> x2.price

Sql data retrieval issue

I have below tables:
Order
Order_id orde_number Order_name
1 12345 iphone
2 67891 samsung
order_event
order_event_no status
1 D
1 C
2 C
I wrote below query to retrieve status not in ('D') like below ,But it gave me 2 records ,
But query should not return because order_no 1 already as status D, even though it has second record C it should not include.
select o.order_number,o.order_name
from order o
join order_event oe
on (o.order_id=oe.order_event_no) where oe.status not in ('D')
Regards,
Chaitu
This will accomplish what you want with your given schema / data...
SELECT order_number, order_name
FROM order
WHERE order_id NOT IN (SELECT order_event_no FROM order_event WHERE status = 'D')
If you want to exclude any order who has a status like 'D' you need a subquery.
select o.order_number,o.order_name
from order o
where oe.order_event_no
NOT IN
(SELECT order_event_no FROM order_event_no WHERE status = 'D')
This is equivalent. Some RDBMs will execute it faster:
Select
o.order_number,
o.order_name
from
order o
where
not exists (
select
'x'
from
order_event oe
where
oe.order_event_no = o.order_id And
oe.status = 'D'
);