I can use Pivot but my table here has only 2 columns so I don't know how to go about with it. A class has maximum of 5 UserIDs so I want to have a ClassID and associated 5 user names.
UserID ClassID
RK980 5
LO567 5
YY667 5
RT223 5
LT987 3
What I need is :
ClassID User1 User2 User3 User4 User5
5 RK980 LO567 YY667 RT223 NULL
3 LT987 NULL NULL NULL NULL
Thank you !
You can use row_number(). I would then tend to go for conditional aggregation rather than pivot:
select classid,
max(case when seqnum = 1 then userid end) as user1,
max(case when seqnum = 2 then userid end) as user2,
max(case when seqnum = 3 then userid end) as user3,
max(case when seqnum = 4 then userid end) as user4,
max(case when seqnum = 5 then userid end) as user5
from (select t.*, row_number() over (partition by classid order by userid) as seqnum
from t
) t
group by classid;
you can use pivot with row_number
DECLARE #MyTable TABLE (UserID VARCHAR(10), ClassID INT)
INSERT INTO #MyTable VALUES
('RK980', 5 ),
('LO567', 5 ),
('YY667', 5 ),
('RT223', 5 ),
('LT987', 3 )
SELECT ClassID, [1] User1, [2] User2, [3] User3, [4] User4, [5] User5 FROM
(SELECT * ,
ROW_NUMBER() OVER(PARTITION BY ClassID ORDER BY UserID ) AS RN
FROM #MyTable ) SRC
PIVOT(MAX(UserID) FOR RN IN ([1], [2], [3], [4], [5])) PVT
Result:
ClassID User1 User2 User3 User4 User5
----------- ---------- ---------- ---------- ---------- ----------
3 LT987 NULL NULL NULL NULL
5 LO567 RK980 RT223 YY667 NULL
Related
This is my original table:
Original table
And I would like it to be as:
CityID | 1 | 2 | 3 | 4 | 5 | 6 | 7
_____________________________________
1024 0800 0900 and so on...
Here is my code, but I get a syntax error near FOR.
select * from
(select SIDURI as CityID, DAY as ArrivalDay, T_FROM as TimeArrival
from RNFIL488) as timingTable
pivot(
timing.SIDURI as CityID
timingTable.T_FROM as TimeArrival
for timing.DAY as ArrivalDay in (
[1],
[2],
[3],
[4],
[5],
[6],
[7]
)
) as pivot_table
Use ROW_NUMBER here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY CityID ORDER BY ArrivalDay) rn
FROM RNFIL488
)
SELECT
CityID,
MAX(CASE WHEN rn = 1 THEN TimeArrival END) AS [1],
MAX(CASE WHEN rn = 2 THEN TimeArrival END) AS [2],
MAX(CASE WHEN rn = 3 THEN TimeArrival END) AS [3],
MAX(CASE WHEN rn = 4 THEN TimeArrival END) AS [4],
MAX(CASE WHEN rn = 5 THEN TimeArrival END) AS [5],
MAX(CASE WHEN rn = 6 THEN TimeArrival END) AS [6],
MAX(CASE WHEN rn = 7 THEN TimeArrival END) AS [7]
FROM cte
GROUP BY
CityID;
This assumes that your original source table would always have 7 arrival days per city. If not, then we might have to use a calendar table to bring in the missing data. Also, I am avoiding the PIVOT operator, because often the above approach performs better (and I also find it much easier to read).
I recommend if you don't have a lot data then you can truncate the table and re-fill table. And don't forget your id column should be unique and use auto_increment on id.
Is there a way to achieve this with hive? I need to count users per segment.
I have a table:
user1, categoryA
user1, categoryB
user2, categoryC
And the desired output would be:
----------------- Category A, Category B, Category C
Category A -- 1 1 0
Category B -- 1 1 0
Category C -- 0 0 1
For static set of categories, this is possible:
with your_data as(
select stack (6,
'user1', 'categoryA',
'user1', 'categoryB',
'user2', 'categoryC',
'user2', 'categoryC',
'user3', 'categoryA',
'user4', 'categoryA'
) as (`user`, category)
)
select
category, sum(catA) as CategoryA, sum(catB) as CategoryB, sum(catC) as CategoryC
from
(
select `user` , category, --each user counted once per category
max(case when category='categoryA' then 1 else 0 end) over (partition by `user`) as catA,
max(case when category='categoryB' then 1 else 0 end) over (partition by `user`) as catB,
max(case when category='categoryC' then 1 else 0 end) over (partition by `user`) as catC
from your_data
group by `user` , category
)s
group by Category
order by category
Result:
category categorya categoryb categoryc
categoryA 3 1 0
categoryB 1 1 0
categoryC 0 0 1
I need to get all the consecutive top row where a column value is equal between them
my table is:
CREATE TABLE [dbo].[Items](
[Id] [int] NOT NULL,
[IdUser] [int] NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[SomeData] nvarchar(50) NOT NULL);
and i want the top rows (ordered by Id desc) with the same IdUser
if table data is:
Id IdUser CreatedDate SomeData
--- ------- ------------------------ --------
1 1 2017-09-21T09:42:01.407Z sdafsasfa
2 1 2017-09-21T09:42:01.407Z sdafsasfa
4 2 2017-09-21T09:42:01.41Z sdafsasfa
5 3 2017-09-21T09:42:01.41Z sdafsasfa
7 3 2017-09-21T09:42:01.413Z sdafsasfa
8 3 2017-09-21T09:42:01.413Z sdafsasfa
9 10 2017-09-21T09:42:01.417Z sdafsasfa
11 11 2017-09-21T09:42:01.417Z sdafsasfa
12 2 2017-09-21T09:42:01.42Z sdafsasfa
15 2 2017-09-21T09:42:01.42Z sdafsasfa
I want :
Id IdUser CreatedDate SomeData
--- ------- ------------------------ --------
12 2 2017-09-21T09:42:01.42Z sdafsasfa
15 2 2017-09-21T09:42:01.42Z sdafsasfa
if table data is:
Id IdUser CreatedDate SomeData
--- ------- ------------------------ --------
1 1 2017-09-21T09:42:01.407Z sdafsasfa
2 1 2017-09-21T09:42:01.407Z sdafsasfa
4 2 2017-09-21T09:42:01.41Z sdafsasfa
I want :
Id IdUser CreatedDate SomeData
--- ------- ------------------------ --------
4 2 2017-09-21T09:42:01.41Z sdafsasfa
SqlFiddle
you can try this query:
select I.*
from
[dbo].[Items] I
JOIN
(select top 1 Id, IdUser from [dbo].[Items] order by Id desc)I2
on I.Iduser=I2.Iduser
order by Id desc;-- this can be removed to remove ordering by Id Desc
updated fiddle link
You could use LAG and SUM() OVER() like this
DECLARE #Items as Table
(
[Id] [int] NOT NULL,
[IdUser] [int] NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[SomeData] nvarchar(50) NOT NULL
);
INSERT INTO #Items
(
Id,
IdUser,
CreatedDate,
SomeData
)
VALUES
( 1 , 1 ,getdate(),'sdafsasfa'),
( 2 , 1 ,getdate(),'sdafsasfa'),
( 4 , 2 ,getdate(),'sdafsasfa'),
( 5 , 3 ,getdate(),'sdafsasfa'),
( 7 , 3 ,getdate(),'sdafsasfa'),
( 8 , 3 ,getdate(),'sdafsasfa'),
( 9 , 10,getdate(),'sdafsasfa'),
( 11, 11,getdate(),'sdafsasfa'),
( 12, 2 ,getdate(),'sdafsasfa'),
( 15, 2 ,getdate(),'sdafsasfa')
;WITH temp AS
(
SELECT *,
CASE
WHEN lag(i.IdUser) over(ORDER BY i.Id) = i.IdUser THEN 0
ELSE 1
END as ChangingPoint
FROM #Items i
),
temp1 AS
(
SELECT
*,
sum(t.ChangingPoint) OVER(ORDER BY t.Id) as GroupId
FROM temp t
)
SELECT TOP 1 WITH TIES
t.Id,
t.IdUser,
t.CreatedDate,
t.SomeData
FROM temp1 t
ORDER BY GroupId DESC
See demo here: http://rextester.com/PHWWU96232
Assuming you want last rows with highest CreateDate and same IdUser then DENSE_RANK will help
SELECT id, iduser, CreatedDate, somedata
FROM (
SELECT id, iduser, CreatedDate, somedata,
DENSE_RANK() OVER (ORDER BY CreatedDate desc, IdUser) ord
FROM [dbo].[Items]) t
WHERE t.ord = 1
The equivalent SQL query is
SELECT *
FROM Items t1
WHERE NOT EXISTS (
SELECT *
FROM Items t2
WHERE t2.createddate > t1.createddate or
(t2.createddate = t1.createddate and t2.iduser < t1.iduser)
)
demo
Despite TriV's solution works fine I ended up using a modified Radim Bača's solution (his solution dont work as i need) because it is faster IMO
SELECT id, iduser, createddate, somedata
FROM Items t1
WHERE NOT EXISTS (
SELECT 1
FROM Items t2
WHERE t2.id > t1.id and t2.iduser <> t1.iduser );
SQLFiddle
select I.*
from
[dbo].[Items1] I
JOIN
(select top 1 Id, IdUser,CreatedDate from [dbo].[Items1] order by Id desc)I2
on I.CreatedDate=I2.CreatedDate
order by Id desc;-- this can be removed to remove ordering by Id Desc
I have a table [Departments] with 2 columns:
[IdDepartment]
[IdSubDepartment]
The table is a kind of hierarchy:
IdDepartment | IdSubDepartment
1 | 2
1 | 3
2 | 4
3 | 5
If I search for department 5 I want to get the following 5 -> 3 -> 1
(I only need the X level every time - not always the root).
I have written a query that gets a department ID and returns its 3rd level (say I enter ID 5 and get back 1). It works fast and good. the problem is when i do that for 7K departments, it gets stuck.
I want to convert the table to a pivot like this:
IdDepartment0 | IdDepartment1 | IdDepartment2 ...
1 2 4
1 3 5
important: I know the level of each department.
so, when I get department 5, I know it is on level 2 (IdDepartment2)
so I can query my new table in no time and get each department level I want.
How do I do convert to the new table?
thanks in advance
Eran
This snipped can be expanded to include deeper nesting.
It can propbably be optimized some.
;WITH cteLvl AS
(
SELECT IdDepartment, IdSubDepartment, 0 AS Lvl
FROM Department
WHERE IdDepartment NOT IN (SELECT IdSubDepartment FROM Department WHERE IdSubDepartment IS NOT NULL)
UNION ALL
SELECT B.IdDepartment, B.IdSubDepartment, A.Lvl + 1
FROM cteLvl A
INNER JOIN Department B ON B.IdDepartment = A.IdSubDepartment
)
, cteLeaf AS
(
SELECT *, ROW_NUMBER() OVER(ORDER BY IdDepartment) AS GroupId
FROM Department
WHERE IdSubDepartment IS NULL
UNION ALL
SELECT B.IdDepartment, B.IdSubDepartment, A.GroupId
FROM cteLeaf A
INNER JOIN Department B ON A.IdDepartment = B.IdSubDepartment
)
, cteCombined AS
(
SELECT A.IdDepartment, A.GroupId, B.Lvl FROM cteLeaf A
INNER JOIN (SELECT DISTINCT IdDepartment, Lvl FROM cteLvl) B ON A.IdDepartment = B.IdDepartment
)
--SELECT * FROM cteCombined
SELECT GroupId, [0] AS Dep0, [1] AS Dep1, [2] AS Dep2, [3] AS Dep3, [4] AS Dep4
FROM
(SELECT GroupId, Lvl, IdDepartment
FROM cteCombined) P
PIVOT
(
SUM(IdDepartment)
FOR Lvl IN
( [0], [1], [2], [3], [4] )
) AS V
Same effect without using the PIVOT construct:
SELECT
GroupId,
MAX(CASE Lvl WHEN 0 THEN IdDepartment END) AS Dep0,
MAX(CASE Lvl WHEN 1 THEN IdDepartment END) AS Dep1,
MAX(CASE Lvl WHEN 2 THEN IdDepartment END) AS Dep2,
MAX(CASE Lvl WHEN 3 THEN IdDepartment END) AS Dep3
FROM cteCombined
GROUP BY GroupId
I have two tables:
CREATE TABLE #A (id int, cond_id int)
INSERT INTO #A (id, cond_id)
VALUES (101,20),
(101,22),
(101,24),
(102,23),
(102,22)
Now, each id can have max of 4 cond_ids. I want to populate table #B so that there is one id and all cond_ids will be populated in the columns as one row according to cond_id ascending.
like for id 102, cond_id 22 goes in cond_id and 23 goes in cond_id2.
create table #B (id int, cond_id1 int, cond_id2 int, cond_id3 int, cond_id4 int)
Desired result:
Table #B
id cond_id1 cond_id2 cond_id3 cond_id4
101 20 22 24 null
102 22 23 null null
Thanks in advance!
Because you know the maximum number of columns, one option is to use row_number, max and case:
with cte as (
select row_number() over (partition by id order by cond_id) rn, id, cond_id
from a)
select id,
max(case when rn = 1 then cond_id end) cond_id1,
max(case when rn = 2 then cond_id end) cond_id2,
max(case when rn = 3 then cond_id end) cond_id3,
max(case when rn = 4 then cond_id end) cond_id4
from cte
group by id
SQL Fiddle Demo
Or you could look at Pivot:
select id, [1] cond_id1, [2] cond_id2, [3] cond_id3, [4] cond_id4
from
(select row_number() over (partition by id order by cond_id) rn, id, cond_id
from a) t
pivot
(
max(cond_id)
for rn in ([1], [2], [3], [4])
) p
More Fiddle