SQL Pivot on two columns - sql

How can I arrange the following result set
meal_type menu_item_id
2 111
2 222
2 333
2 444
2 555
3 666
3 777
3 888
3 999
to
2 3
111 666
222 777
333 888
444 999
555
using pivot or unpivot

The problem with your data - no source for group, PIVOT assumes aggregate function
If you data are small (it is subject for separate topic :-) ), you can create grouping field, using ROW_NUMBER() function. I assume source table name is "test"
with ordered as (
select
row_number() OVER (PARTITION by meal_type order by menu_item_id) num,
* from [test]
)
select
max(case [meal_type] when 2 then [menu_item_id] end) as [2],
max(case [meal_type] when 3 then [menu_item_id] end) as [3]
from ordered group by num

You can achieve the result using ROW_NUMBER and PIVOT:
SELECT [2] ,
[3]
FROM ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY meal_type ORDER BY menu_item_id ) R
FROM dbo.Meal
) s PIVOT( MAX(menu_item_id) FOR meal_type IN ( [2], [3] ) ) pvt;

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

Breaking Child Data Into Multiple records based on Parent ID

I have a requirement where i need to break child data into multiple records .Below,im trying to make you understand with some sample date
as i should not post original data . In the below data for every ParentId we may have multiple child records.So,now
we need to display every record with 3 child's data in separate columns along with their corresponding Parent Id as shown in below expected output.
We have tried with cursors even though we got but it it is killing the execution time and also we have thought of using pivot and seems like it become much complex and i'm not sure it may work .
Any help or approach will be appreciated.Thanks in advance.
Parent Table
SELECT * into #Parent FROM (
SELECT 1 PARENTID,'A' PARENTNAME
UNION ALL
SELECT 2,'B'
UNION ALL
SELECT 3,'C'
UNION ALL
SELECT 4,'D'
) AS A
Child Table
SELECT * INTO #Child from (
SELECT 10 as CHILDID,1 as PARENTID ,'DEF' AS CHILDNAME
union all
SELECT 11 , 1,'EFG'
UNION ALL
SELECT 12,1,'GHI'
UNION ALL
SELECT 13,1,'JKL'
UNION ALL
SELECT 14,1,'MNO'
UNION ALL
SELECT 15,1,'PQR'
UNION ALL
SELECT 20,2,'ACE'
UNION ALL
SELECT 30,3,'STU'
UNION ALL
SELECT 31,3,'VWX'
UNION ALL
SELECT 32,3,'WXY'
UNION ALL
SELECT 33,3,'XYZ'
)as a
SELECT * FROM #Parent
SELECT * FROM #CHILD
Expected Result:
PARENTID Child1Name Child2Name Child3Name
1 DEF EFG GHI
1 JKL MNO PQR
2 ACE NULL NULL
3 STU VWX WXY
3 XYZ NULL NULL
Generate the two row_numbers using row_number() function no need for cursor
SELECT
p.PARENTID,
coalesce(max(case when c.rn1=1 then c.ChildName end), max(case when c.rn1%3=1 then c.ChildName end)) [Child1Name],
coalesce(max(case when c.rn1=2 then c.ChildName end), max(case when c.rn1%3=2 then c.ChildName end)) [Child2Name],
coalesce(max(case when c.rn1=3 then c.ChildName end), max(case when c.rn1%3=0 then c.ChildName end)) [Child3Name]
FROM Parent p
join
(SELECT *, (row_number() over (partition by PARENTID order by childid)-1)/3 rn,
row_number() over (partition by PARENTID order by childid) rn1 FROM CHILD) c on c.PARENTID = p.PARENTID
group by p.PARENTID, c.rn
order by p.PARENTID
Result :
PARENTID Child1Name Child2Name Child3Name
1 DEF EFG GHI
1 JKL MNO PQR
2 ACE NULL NULL
3 STU VWX WXY
3 XYZ NULL NULL
Use NTILE & ROW_NUMBERfor deviding them into group of 3 records
SELECT PARENTID,CHILD1, CHILD2,CHILD3 FROM (
SELECT 'CHILD'+CASE WHEN grp='0' THEN '3' ELSE grp END CHILDS
,CAST(NTILE(2) OVER(PARTITION BY PARENTID ORDER BY CHILDID) AS VARCHAR(10))
+'-' +CAST(PARENTID AS VARCHAR(10)) as PARENTID_2
, PARENTID, CHILDNAME FROM (
SELECT CAST(ROW_NUMBER() OVER (PARTITION BY PARENTID ORDER BY CHILDID)%3 AS VARCHAR(10))
AS grp
,* FROM #CHILD
)A
)B
PIVOT
(
MAX(CHILDNAME) FOR CHILDS IN([CHILD1],[CHILD2],[CHILD3])
)PV
Result:
+----------+--------+--------+--------+
| PARENTID | CHILD1 | CHILD2 | CHILD3 |
+----------+--------+--------+--------+
| 1 | DEF | EFG | GHI |
| 1 | JKL | MNO | PQR |
| 2 | ACE | NULL | NULL |
| 3 | STU | VWX | NULL |
| 3 | XYZ | NULL | WXY |
+----------+--------+--------+--------+
Major rewrite of original answer, you just need one PIVOT, two ROW_NUMBER, and that's all:
SELECT PARENTID, [0], [1], [2]
FROM (
SELECT
PARENTID
, CHILDNAME
, ParentBreaker = (ROW_NUMBER() OVER(PARTITION BY PARENTID ORDER BY CHILDID) - 1) / 3 + 1 -- You want this to facilitate splitting every 3 child records.
, Child#Name = (ROW_NUMBER() OVER(PARTITION BY PARENTID ORDER BY CHILDID) - 1) % 3
FROM #Child
) AS RowNumbered
PIVOT (
MAX(CHILDNAME)
FOR Child#Name IN ([0], [1], [2])
) AS T
ORDER BY PARENTID
With a quick CONCAT and a +1 on Child#Name, you can probably simulate the column names in your "expected result" as well.

I want first and second inserted value with condition

Table abc:
Consgno Name Entrydatetime
111 A 01/03/2017 10:10:15
111 A 01/03/2017 10:20:15
111 A 01/03/2017 11:10:20
222 B 02/03/2017 10:10:25
333 C 06/03/2017 10:10:25
333 C 07/03/2017 10:10:12
444 D 04/03/2017 10:10:41
444 D 04/03/2017 01:10:20
444 D 06/03/2017 10:10:32
555 E 05/04/2017 10:10:15
One Consgno has entered ONE more than one time.
When one Consgno is only once, then the first value should come, otherwise the second entered value should come.
I want to output like this:
Consgno Name Entrydatetime
111 A 01/03/2017 10:20:15
222 B 02/03/2017 11:10:36
333 C 07/03/2017 10:10:12
444 D 04/03/2017 01:10:20
555 E 05/04/2017 10:10:15
You can use a query like the following:
;WITH MyWindowedTable AS (
SELECT Consgno, Name, Entrydatetime,
ROW_NUMBER() OVER (PARTITION BY Consgno
ORDER BY Entrydatetime) AS rn,
COUNT(*) OVER (PARTITION BY Consgno) AS cnt
FROM mytable
)
SELECT Consgno, Name, Entrydatetime
FROM MyWindowedTable
WHERE (cnt = 1 AND rn = 1) OR (cnt > 1 AND rn = 2)
Using windowed version of COUNT:
COUNT(*) OVER (PARTITION BY Consgno)
returns the population, cnt, of each Consgno partition. We can use cnt to properly filter the records returned: in partitions with a population of 1 we get the single record of the partition, whereas in the rest of the cases we get the one having rn = 2.
Use ROW_NUMBER and COUNT built in functions :
CREATE TABLE #table1 ( Consgno INT, Name VARCHAR(1), Entrydatetime
DATETIME)
INSERT INTO #table1 ( Consgno , Name , Entrydatetime )
SELECT 111,'A','01/03/2017 10:10:15' UNION ALL
SELECT 111,'A','01/03/2017 10:20:15' UNION ALL
SELECT 111,'A','01/03/2017 11:10:20' UNION ALL
SELECT 222,'B','02/03/2017 10:10:25' UNION ALL
SELECT 333,'C','06/03/2017 10:10:25' UNION ALL
SELECT 333,'C','07/03/2017 10:10:12' UNION ALL
SELECT 444,'D','04/03/2017 10:10:41' UNION ALL
SELECT 444,'D','04/03/2017 01:10:20' UNION ALL
SELECT 444,'D','06/03/2017 10:10:32' UNION ALL
SELECT 555,'E','05/04/2017 10:10:15'
SELECT Consgno , Name , Entrydatetime
FROM
(
SELECT Consgno , Name , Entrydatetime , ROW_NUMBER() OVER (PARTITION BY
Consgno ORDER BY Entrydatetime) RNo , COUNT(*) OVER (PARTITION BY
Consgno) AS _Count
FROM #table1
) A WHERE ( RNo = 1 AND _Count = 1) OR (_Count > 1 AND RNo = 2 )

Need SQL to get top row

I'm using a SQL Server database and have this data:
Loc dept deptdesc
-----------------------
1 201 ccccc
1 201 fffff
1 201 uuu
2 202 lllll
3 203 ooo
3 203 yyy
3 203 mmm
3 203 bbbb
I need help with the SQL query to get data:
Loc dept deptdesc
----------------------------
1 201 ccccc
2 202 lllll
3 203 ooo
You stated in your comments that it can be any of the descriptions, assuming this is true a simple group by will work.
SELECT Loc, dept, MIN(deptdesc)
FROM YourTable
GROUP BY Loc, dept
You can do this using Row_Number() and only taking the first of each group.
;With Cte As
(
Select *, Row_Number() Over (Partition By Dept Order By (Select Null)) As RN
From YourTable
)
Select Loc, Dept, DeptDesc
From Cte
Where RN = 1
Use the below query.. You can use CTE.
WITH cte_1
AS
( Select Loc,Dept,DeptDesc
,Row_number()over(partition by Loc,Dept Order by (select 1)) as RNO
From YourTable)
Select Loc,Dept,DeptDesc
From cte_1
Where RNO =1
Have assumed there is a surrogate id
WITH firstVal AS(
SELECT
DISTINCT first_value(column4) OVER(PARTITION BY column1 ORDER BY column2 ) AS id
FROM
(VALUES
(1,201,'ccccc',100)
,(1,201,'fffff',101)
,(1,201,'uuu',102),
(2,202,'lllll',103),
(3,203,'ooo',104),
(3,203,'yyy',105),
(3,203,'mmm',106),
(3,203,'bbbb',107)
)
)
SELECT
column1,column2,column3
FROM
(VALUES
(1,201,'ccccc',100)
,(1,201,'fffff',101)
,(1,201,'uuu',102),
(2,202,'lllll',103),
(3,203,'ooo',104),
(3,203,'yyy',105),
(3,203,'mmm',106),
(3,203,'bbbb',107)
) vals
INNER JOIN firstVal ON firstVal.id = vals.column4

Help needed in pivoting (SQL Server 2005)

I have a table like
ID Grps Vals
--- ---- -----
1 1 1
1 1 3
1 1 45
1 2 23
1 2 34
1 2 66
1 3 10
1 3 17
1 3 77
2 1 144
2 1 344
2 1 555
2 2 11
2 2 22
2 2 33
2 3 55
2 3 67
2 3 77
The desired output being
ID Record1 Record2 Record3
--- ------- ------- -------
1 1 23 10
1 3 34 17
1 45 66 77
2 144 11 55
2 344 22 67
2 555 33 77
I have tried(using while loop) but the program is running slow. I have been asked to do so by using SET based approach. My approach so far is
SELECT ID,[1] AS [Record1], [2] AS [Record2], [3] as [Record3]
FROM (
Select
Row_Number() Over(Partition By ID Order By Vals) records
,*
From myTable)x
PIVOT
(MAX(vals) FOR Grps IN ([1],[2],[3])) p
But it is not working.
Can any one please help to solve this.(SQL SERVER 2005)
You were almost there! All I had to do was add the necessary columns to the Partition By and Order By clauses, and it worked:
SELECT ID,[1] AS [Record1], [2] AS [Record2], [3] as [Record3]
FROM (
Select
Row_Number() Over(Partition By id, grps Order By id, grps, vals) records
,*
From myTable)x
PIVOT
(MAX(vals) FOR Grps IN ([1],[2],[3])) p
A simpler approach that would not involve the use of PIVOT would something like:
;With ItemGroups As
(
Select Id, Grps, Vals
, Row_Number() Over ( Partition By Id, Grps Order By Vals ) As RowNum
From myTable
)
Select Id
, Max( Case When Grps = 1 Then Vals End )
, Max( Case When Grps = 2 Then Vals End )
, Max( Case When Grps = 3 Then Vals End )
From ItemGroups
Group By Id, RowNum
Order By Id
This may not apply to you but if your using a while loop like....
while( x<Total.length() ){
....do something
}
you should declare Total.length outside of the loop assigned to a variable...
int spoon= Total.length();
while( x< spoon ){
....do something
}
or else
you calculate the number Total.length()every time the loop runs