Given a table sale where id is not unique:
id name item quantity
1 Darsh shoes 5
2 Liyah oil 1
2 Eiliyah watch 1
3 Zakaria notebook 2
3 Elliot shirt 3
4 Reese bag 1
I need to select all unique ids for a row and not loose any data(like for id in (2,3) where both name,item and quantity should be displayed in same row).Also there are maximum of 2 same id in sale table.
I tried using row_number() to get some unique pattern(s).
From this query :
Select a.id,a.name,a.item,a.quantity,b.name as name2,b.item as item2,b.quantity as quantity2
,row_number() over(partition by a.id order by a.id) as f1
,row_number() over(partition by a.name order by a.id) as f2
from sale a inner join sale b on a.id = b.id
I got this
id name item quantity name2 item2 quantity2 f1 f2
1 Darsh shoes 5 Darsh shoes 5 1 1
2 Eiliyah watch 1 Liyah oil 1 2 1
2 Eiliyah watch 1 Eiliyah watch 1 4 2
3 Elliot shirt 3 Zakaria notebook 2 2 1
3 Elliot shirt 3 Elliot shirt 3 4 2
2 Liyah oil 1 Eiliyah watch 1 3 1
2 Liyah oil 1 Liyah oil 1 1 2
4 Reese bag 1 Reese bag 1 1 1
3 Zakaria notebook 2 Elliot shirt 3 3 1
3 Zakaria notebook 2 Zakaria notebook 2 1 2
Now here the problem,If I filter f1,f2 and use IIF for remove repetitive data using this query :
Select id,name,item,quantity
,iif(name = name2,NULL,name2) as name2
,iif(item = item2,NULL,item2) as item2
,iif(quantity = quantity2,NULL,quantity2) as quantity2
from (
Select a.id,a.name,a.item,a.quantity,b.name as name2,b.item as item2,b.quantity as quantity2
,row_number() over(partition by a.id order by a.id) as f1
,row_number() over(partition by a.name order by a.id) as f2
from sale a inner join sale b on a.id = b.id
)t
where (f1=1 and f2=1) or(f1=3 and f2=1)
order by id
then quantity2 is (null) in 2nd row as shown below.
id name item quantity name2 item2 quantity2
1 Darsh shoes 5 NULL NULL NULL
2 Liyah oil 1 Eiliyah watch NULL
3 Zakaria notebook 2 Elliot shirt 3
4 Reese bag 1 NULL NULL NULL
So, there can be same quantity for different item and name.
Expected result:
id name item quantity name2 item2 quantity2
1 Darsh shoes 5 NULL NULL NULL
2 Liyah oil 1 Eiliyah watch 1
3 Zakaria notebook 2 Elliot shirt 3
4 Reese bag 1 NULL NULL NULL
Please help me.
Thanks!
One method is conditional aggregation . . . if you know that there are at most two duplicates per id:
select id,
max(case when seqnum = 1 then name end) as name_1,
max(case when seqnum = 1 then item end) as item_1,
max(case when seqnum = 1 then quantity end) as quantity_1,
max(case when seqnum = 2 then name end) as name_2,
max(case when seqnum = 2 then item end) as item_2,
max(case when seqnum = 2 then quantity end) as quantity_2
from (select s.*,
row_number() over (partition by id order by id) as seqnum
from sale s
) s
group by id;
As per your expected result .You can create temp(or Intermediate table) and as there are maximum of same two id ,then this can be your answer:
select *,row_number() over (partition by id order by id) as u_id into #test from sale
select * from (select * from #test where u_id=1) a
left join (select * from #test where u_id=2)b
on a.id = b.id
Related
I have a table that looks something like this:
id name status
2 a 1
2 a 2
2 a 3
2 a 2
2 a 1
3 b 2
3 b 1
3 b 2
3 b 1
and the resultant i want is:
id name total count count(status3) count(status2) count(status1)
2 a 5 1 2 2
3 b 4 0 2 2
please help me get this result somehow, i can just get id, name or one of them at a time, don't know how to put a clause to get this table at once.
Here's a simple solution using group by and case when.
select id
,count(*) as 'total count'
,count(case status when 3 then 1 end) as 'count(status1)'
,count(case status when 2 then 1 end) as 'count(status3)'
,count(case status when 1 then 1 end) as 'count(status2)'
from t
group by id
id
total count
count(status3)
count(status2)
count(status1)
2
5
1
2
2
3
4
0
2
2
Fiddle
Here's a way to solve it using pivot.
select *
from (select status,id, count(*) over (partition by id) as "total count" from t) tmp
pivot (count(status) for status in ([1],[2],[3])) pvt
d
total count
1
2
3
3
4
2
2
0
2
5
2
2
1
Fiddle
Sample Input:
ID
Vals
1
Product
2
Milk
3
Butter
4
Cheese
5
Yogurt
6
Product
7
Muesli
8
Porridge
9
Product
10
Banana
Sample Output:
ID
Vals
RANK
1
Product
1
2
Milk
1
3
Butter
1
4
Cheese
1
5
Yogurt
1
6
Product
2
7
Muesli
2
8
Porridge
2
9
Product
3
10
Banana
3
This looks like a conditional cumulative sum:
select t.*,
sum(case when vals = 'Product' then 1 else 0
end) over (order by id) as ranking
from t
order by id;
you also can use window function:
SELECT * , SUM(CASE WHEN Vals ='Product' THEN 1 END) OVER (ORDER BY id) ranking
FROM tableName
Assuming your table is sorted by ID:
SELECT T.ID,
T.Vals,
(SELECT COUNT(DISTINCT ID) FROM table WHERE Vals = 'Product' AND ID <= T.ID) as Rank
FROM table T
I have the following table:
WorkID WorkDesc
--------------------
1 ABCD
2 DEFG
3 HIJK
then I've the following table as the detail of table one:
WorkDetailID WorkID WorkDetailDesc
-----------------------------------------
1 1 001
2 1 002
3 2 006
4 2 007
5 3 015
Each WorkID is always have maximum 2 records and minimum is 1.
I want to have the following result:
WorkID WorkDesc WorkDetailID1 WorkDetailID2
-------------------------------------------------------
1 ABCD 1 2
2 DEFG 3 4
3 HIJK 5 null
Does anyone have an idea how to do that?
Thank you.
You can use pivot. I prefer conditional aggregation. In either case, you need a column for the pivoting. row_number() to the rescue:
select t1.workid, t1.workdesc,
max(case when t2.seqnum = 1 then t2.workdetailid end) as workdetailid1,
max(case when t2.seqnum = 2 then t2.workdetailid end) as workdetailid2
from t1 join
(select t2.*,
row_number() over (partition by t2.workid order by t2.workdetailid) as seqnum
from t2
) t2
on t1.workid = t2.workid
group by t1.workid, t1.workdesc
I have 3 tables which maintains stock entries for each products/items. These three tables like below :
Table : ItemStock (to maintain remaining stock of each item)
Id ItemId OpgQty BranchID CurrentStock
1 7 0 1 8
2 7 0 2 3
3 6 0 1 2
4 6 0 2 0
Table : ItemPurchase (StockIn)
Id ItemId Qty BranchID
1 7 5 1
2 7 4 2
3 7 6 1
4 7 2 2
5 6 4 1
6 6 2 2
7 6 2 1
Table : ItemSale (StockOut)
Id ItemId Qty BranchID
1 7 2 1
2 7 3 2
3 7 1 1
4 6 4 1
5 6 2 2
Desired Output (based on sql queries)
I want to have result like below : (part of report)
Id ItemId OpgQty BranchId StockIn StockOut CurrentStock
1 7 0 1 11 3 8
2 7 0 2 6 3 3
3 6 0 1 6 4 2
4 6 0 2 2 2 0
I was trying to get the desired result but was not able to do so. Please help!!!
try this;
select
m.Id,
m.ItemId,
m.OpgQty,
m.BranchID,
si.StockIn,
m.CurrentStock-si.StockIn StockOut,
m.CurrentStock
from
ItemStock m
inner join
(
select
ItemId,BranchId,sum(Qty) as StockIn
from
ItemPurchase
group by ItemId,BranchId
) si on si.ItemId=m.ItemId and si.BranchId=m.BranchId
A very simple query that gives the desired result is :
select *,
(select sum(Qty)
from ItemPurchase
where ItemPurchase.ItemId = ItemStock.ItemId and
ItemPurchase.BranchId = ItemStock.BranchId) as StockIn,
(select sum(Qty)
from ItemSale
where ItemSale.ItemId = ItemStock.ItemId and
ItemSale.BranchId = ItemStock.BranchId) as StockOut
from ItemStock
Two subqueries with group by and aggregation will get what you want.
select
s.*,
coalesce([ip].StockIn, 0) as StockIn, -- In case of no records in ItemPurchase or ItemSale, coalesce is neccessary.
coalesce([is].StockOut, 0) as StockOut
from ItemStock s
left join (
select sum(Qty) as StockIn, ItemId, BranchId
from ItemPurchase
group by ItemId, BranchId
) [ip] on s.ItemId = [ip].ItemId and s.BranchId = [ip].BranchId
left join (
select sum(Qty) as StockOut, ItemId, BranchId
from ItemSale
group by ItemId, BranchId
) [is] on s.ItemId = [is].ItemId and s.BranchId = [is].BranchId
See demo in sqlfiddle.
Please
Try This ... I hope you consider this too.
thanks in advance for the help and sorry for how the "table" looks. Here's my question...
Let's say I have a subquery with this table (imagine the bold as column headers) as its output -
id 1 1 2 3 3 3 3 4 5 6 6 6
action o c o c c o c o o c c c
I would like my new query to output -
id 1 1 2 3 3 3 3 4 5 6 6 6
action o c o c c o c o o c c c
ct 1 2 1 1 2 3 4 1 1 1 2 3
#c 0 1 0 1 2 2 3 0 0 1 2 3
#o 1 1 1 0 0 1 1 1 1 0 0 0
where ct stands for count. Basically, I want to count (for each id) the occurrences of consecutive id and action as they happen. Let me know if this makes sense, and if not, how I can clarify my question.
Note: I realize the lag/lead functions may be helpful in this situation, along with the row_number() function. Looking for as many creative solutions as possible!
You are looking for the row_number() analytic function:
select id, action, row_number() over (partition by id order by id) as ct
from table t;
For #c and #o, you want cumulative sum:
select id, action, row_number() over (partition by id order by id) as ct,
sum(case when action = 'c' then 1 else 0 end) over
(partition by id order by <some column here>) as "#c",
sum(case when action = 'c' then 1 else 0 end) over
(partition by id order by <some column here>) as "#o"
from table t;
The one caveat is that you need a way to specify the order of the rows -- an id or date time stamp or something. SQL result sets and tables are inherently unordered, so there is no idea that one row comes before or after another.
SQL> select id, action,
2 row_number() over(partition by id order by rowid) ct,
3 sum(decode(action,'c',1,0)) over(partition by id order by rowid) c#,
4 sum(decode(action,'o',1,0)) over(partition by id order by rowid) o#
5 from t1
6 /
ID A CT C# O#
---------- - ---------- ---------- ----------
1 o 1 0 1
1 c 2 1 1
2 o 1 0 1
3 c 1 1 0
3 c 2 2 0
3 o 3 2 1
3 c 4 3 1
4 o 1 0 1
5 o 1 0 1
6 c 1 1 0
6 c 2 2 0
6 c 3 3 0
P.S. Sorry Gordon, didn't see your post.