Partial pivot without pivot operator - sql

I am looking for a query to partially pivot a table without using the PIVOT operator (old ms-sql server).
the table:
id-------item---------rank1---------rank2
231------it1--------- 1 ----------- 1
231------it2-------- 1 ----------- 2
231------it3--------- 1 ----------- 3
154------it4--------- 3 ----------- 4
154------it2--------- 1 ----------- 2
155------it2--------- 1 ----------- 2
156------it3 -------- 2 ----------- 2
156------it1 -------- 1 ----------- 1
expected result:
id---------item1----item2----item3---item*...
231 -------it1------it2---------it3
154--------it2------it4
155--------it2
156--------it1------it3
order by rank1 and rank2
I searched on google but the solution I found was too complicated to apply.

In SQL Server, you could use row_number to assign a row number for each id group. Then you can use the max(case(... trick to pivot:
select id
, max(case when rn = 1 then item end) as item1
, max(case when rn = 2 then item end) as item2
, max(case when rn = 3 then item end) as item3
from (
select row_number() over (partition by id
order by rank1, rank2) as rn
, *
from YourTable
) as SubQueryAlias
group by
id
There is no general solution for N items without using dynamic SQL.

Related

DB2 Toad SQL - Group by Certain Columns using Max Command

I am having some trouble with the below query. I do understand I need to group by ID and Category, but I only want to group by ID while keeping the rest of the columns based on Rank being max. Is there a way to only group by certain columns?
select ID, Category, max(rank)
from schema.table1
group by ID
Input:
ID Category Rank
111 3 4
111 1 5
123 5 3
124 7 2
Current Output
ID Category Rank
111 3 4
111 9 1
123 5 3
124 7 2
Desired Output
ID Category Rank
111 1 5
123 5 3
124 7 2
You can use:
select *
from table1
where (id, rank) in (select id, max(rank) from table1 group by id)
Result:
ID CATEGORY RANK
---- --------- ----
111 1 5
123 5 3
124 7 2
Or you can use the ROW_NUMBER() window function. For example:
select *
from (
select *,
row_number() over(partition by id order by rank desc) as rn
from table1
) x
where rn = 1
See running example at db<>fiddle.
You can try using - row_number()
select * from
(
select ID, Category,rank, row_number() over(partition by id order by rank desc) as rn
from schema.table1
)A where rn=1

Generate row index for table based on last updated date

I would like to generate an index row in a table that may contain duplicates. the index need to be based on values from the table and last update date.
The data looks like this:
ID Val1 LastUpdateDate
-- ------ -------------
1 0 07.09.2019
1 2.5 12.09.2019
1 2.5 27.09.2019
1 3.5 01.10.2019
1 2.5 24.10.2019
1 0 01.11.2019
I would like to have:
ID Val1 LastUpdateDate index
-- ------ ------------- ----
1 0 07.09.2019 1
1 2.5 12.09.2019 2
1 2.5 27.09.2019 2
1 3.5 01.10.2019 3
1 2.5 24.10.2019 4
1 0 01.11.2019 5
I've tried with the following code but it's not working:
SELECT ID
,Value1
,Value2
,Value3
,LastUpdateDate
,(ROW_NUMBER() OVER (PARTITION BY ID ORDER BY last_update_date) - ROW_NUMBER()OVER(PARTITION BY ID,Value1,Value2,Value3 ORDER BY ID,Value1,Value2,Value3)) AS index
FROM Table1
ORDER BY LastUpdateDate
You can interpret this as a gaps-and-islands problem. However, I think the simplest way is to use LAG() and count the changes:
You seem to want dense_rank():
SELECT t1.*,
SUM(CASE WHEN prev_val1 = val1 THEN 0 ELSE 1 END) OVER (PARTITION BY id ORDER BY last_update_date) as seqnum
FROM (SELECT t1.*,
LAG(val1) OVER (PARTITION BY ID ORDER BY last_update_date) as prev_val1
FROM Table1 t1
) t1
ORDER BY LastUpdateDate;
Note that index is a really bad name for a column, because it is a SQL keyword.

DENSE_RANK() Query

I have something similar to the below dataset...
ID RowNumber
101 1
101 2
101 3
101 4
101 5
101 1
101 2
What I would like to get is an additional column as below...
ID RowNumber New
101 1 1
101 2 1
101 3 1
101 4 1
101 5 1
101 1 2
101 2 2
I have toyed with dense_rank(), but no such luck.
Gordon already mentioned, you required a column to specify the order of data. If i consider ID as order by column, this following logic may help you to get your desired result-
WITH your_table(ID,RowNumber)
AS
(
SELECT 101,1 UNION ALL
SELECT 101,2 UNION ALL
SELECT 101,3 UNION ALL
SELECT 101,4 UNION ALL
SELECT 101,5 UNION ALL
SELECT 101,1 UNION ALL
SELECT 101,2
)
SELECT A.ID,A.RowNumber,
SUM(RN) OVER
(
ORDER BY ID
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) +1 New
FROM
(
SELECT *,
CASE
WHEN LAG(RowNumber) OVER(ORDER BY ID) > RowNumber THEN 1
ELSE 0
END RN
FROM your_table
)A
Above will always change the ROW NUMBER if the value in RowNumber decreased than previous one. Alternatively, the same output alsoo can be achieved if you wants to change row number whenever value 1 found. This is bit static option-
SELECT A.ID,A.RowNumber,
SUM(RN) OVER
(
ORDER BY ID
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) New
FROM(
SELECT *,
CASE
WHEN RowNumber = 1 THEN 1
ELSE 0
END RN
FROM your_table
)A
Output is-
ID RowNumber New
101 1 1
101 2 1
101 3 1
101 4 1
101 5 1
101 1 2
101 2 2
SQL tables represent unordered sets. There is no ordering unless a column specifies the ordering.
Assuming you have such a column, you can do what you want simply by counting the number of "1" up to each point:
select t.*,
sum(case when rownumber = 1 then 1 else 0 end) over (partition by id order by <ordering column>) as new
from t;
As Gordon alluded to, there is no default order in your example so it's difficult to imagine how to get a deterministic result (e.g. where the same values supplied to the same query always resulting in the exact same answer.)
This sample data includes a sequential PK column which is used to define the order of this set.
DECLARE #tbl TABLE (PK INT IDENTITY, ID INT, RowNumber INT)
INSERT #tbl(ID, RowNumber) VALUES (101,1),(101,2),(101,3),(101,4),(101,5),(101,1),(101,2);
SELECT t.* FROM #tbl AS t;
Returns:
PK ID RowNumber
----- ------ -----------
1 101 1
2 101 2
3 101 3
4 101 4
5 101 5
6 101 1
7 101 2
This query uses DENSE_RANK to get you what you want:
DECLARE #tbl TABLE (PK INT IDENTITY, ID INT, RowNumber INT)
INSERT #tbl(ID, RowNumber) VALUES (101,1),(101,2),(101,3),(101,4),(101,5),(101,1),(101,2);
SELECT t.ID, t.RowNumber, New = DENSE_RANK() OVER (ORDER BY t.PK - RowNumber)
FROM #tbl AS t;
Returns:
ID RowNumber New
----- ----------- ------
101 1 1
101 2 1
101 3 1
101 4 1
101 5 1
101 1 2
101 2 2
Note that ORDER BY New does not affect the plan.
Please try the below
Load the data into Temp table
Select id,RowNumber,Row_number()over(partition by RowNumber Order by id)New from #temp
Order by Row_number()over(partition by RowNumber Order by id),RowNumber

How to Generate Row number Partition by two column match in sql

Tbl1
---------------------------------------------------------
Id Date Qty ReOrder
---------------------------------------------------------
1 1-1-18 1 3
2 2-1-18 0 3
3 3-1-18 2 3
4 4-1-18 3< >3
5 5-1-18 2 3
6 6-1-18 0 3
7 7-1-18 1 3
8 8-1-18 0 3
---------------------------------------------------------
I want the result like below
---------------------------------------------------------
Id Date Qty ReOrder
---------------------------------------------------------
1 1-1-18 1 3
5 5-1-18 2 3
---------------------------------------------------------
if ReOrder not same with Qty then date will be same upto after reorder=Qty
You can use cumulative approach with row_number() function :
select top (1) with ties *
from (select *, max(case when qty = reorder then 'v' end) over (order by id desc) grp
from table
) t
order by row_number() over(partition by grp order by id);
Unfortunately this will require SQL Server, But you can also do:
select *
from (select *, row_number() over(partition by grp order by id) seq
from (select *, max(case when qty = reorder then 'v' end) over (order by id desc) grp
from table
) t
) t
where seq = 1;

Oracle SQL : Pivot a column

I have table structure like below :
product supplier price qty
------- -------- ----- ---
SOAP ABC 50 10
SOAP DCE 50 10
BRUSH FGH 30 5
I would like to transform this table into :
product supplier_1 supplier_2 price qty
------- -------- ---------- ----- ---
SOAP ABC DCE 50 10
BRUSH FGH 30 5
how can I do it in SQL? thanks in advance.
Maybe this helps:
select product,
max(case when rn = 1 then supplier end) as supplier_1,
max(case when rn = 2 then supplier end) as supplier_2,
-- ...
-- max(case when rn = n then supplier end) as supplier_n,
avg(price) as price,
sum(qty) as sum
from(select t.*,
row_number() over (partition by product order by supplier) rn
from your_table t
)
group
by product;
select product,supplier_1,supplier_2,price,qty from table
model
return all rows
dimension by(product)
measures(supplier,
lpad(' ',10) supplier_1,
lpad(' ',10) supplier_2
)
rules upsert(
supplier_1[0] = supplier['SOAP'],
supplier_2[0] = supplier['BRUSH']
)
10G or 10G above available.