Sqlserver predict top5 records but various group - mathematical logic - sql-server

I have table like below,
user_id Task_name Score
__________________________________
1 101 10
1 102 9
1 103 8
2 104 10
2 105 9
3 106 9
4 107 9
4 108 8
5 109 8
5 110 7
5 111 6
6 112 10
6 113 9
6 114 8
7 115 9
7 116 8
I want to take top 5 score or max 5 Tasks.
Condition:
1) At least try to get one Tasks from one user.
Output:
User_Id Task_Name Score
____________________________________
1 101 10
2 104 10
6 112 10
3 106 9
4 107 9

I think this is what you need:
SELECT TOP 5 User_id, Task_name, Score
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY Score DESC) R
FROM Src
) T
ORDER BY R, Score DESC, user_id
It yields:
User_Id Task_Name Score
____________________________________
1 101 10
2 104 10
6 112 10
3 106 9
4 107 9
If you need top 5 ordered, wrap results with another SELECT..ORDER clauses:
SELECT * FROM
(
SELECT TOP 5 user_id, Task_name, Score
FROM
(
SELECT *, RANK() OVER (PARTITION BY user_id ORDER BY Score DESC) R
FROM Src
) T
ORDER BY R, Score DESC, user_id
) E
ORDER BY Score DESC, user_id

I think this is what you want:
select top 5 t.*
from (select t.*,
row_number() over (partition by user_id order by score desc) as seqnum
from t
) t
where seqnum = 1
order by score desc;
The row_number() is used to select the best row for each user. The outer query then chooses the top 5 users with the tasks.

Related

SQL - Select non repeating columns

I have a table like
id name R_id mgr_id
----------------------------
61 a 22 1
62 a 22 2
62 b 23 1
63 c 24 4
63 b 22 3
64 c 25 3
and I would like to get the following result set
R_id mgr_id
--------------
22 1
23 1
24 4
25 3
I would like select repeating R_ids only once
I tried using this query but with not much success, can anyone help me.
SELECT DISTINCT R_id, mgr_id from DT
Perhaps something like this... WITH TIES clause in concert with Row_NUmber()
Example
Select Top 1 with ties
R_ID
,mgr_id
From #YourTable
Order By Row_Number() over (Partition By R_ID order by Mgr_id)
Returns
R_ID mgr_id
22 1
23 1
24 4
25 3

Latest record for each user number?

I did search, but the uniqueness of each question makes it hard for me to "translate" it for my dataset.
I have table A named: CLOGS17
With a sub-set of the data and fields shown:
SERIALNO EVDATE SYSNO AREA USRNO
4 2017-01-01 02:03:48.000 1 4 10
4 2017-01-01 02:09:00.000 1 4 10
4 2017-01-01 02:24:44.997 1 6 10
4 2017-01-01 02:56:50.000 1 2 18
5 2017-08-08 02:03:48.000 1 4 10
5 2017-01-09 02:09:00.000 1 4 10
6 2017-04-03 02:24:44.997 1 6 10
8 2017-05-05 02:56:50.000 1 2 18
My goal is to retrieve all records where the combination of SERIALNO + SYSNO + AREA + USRNO has not been used in the last 30 days (inactive user essentiallY) so I can delete that USRNO.
Desired output from above data would be (newest record for each SERIALNO, SYSNO, AREA, and USRNO distinct combination):
SERIALNO EVDATE SYSNO AREA USRNO
4 2017-01-01 02:09:00.000 1 4 10
4 2017-01-01 02:24:44.997 1 6 10
4 2017-01-01 02:56:50.000 1 2 18
5 2017-08-08 02:03:48.000 1 4 10
6 2017-04-03 02:24:44.997 1 6 10
8 2017-05-05 02:56:50.000 1 2 18
I am then able to get only those within the last 30 days.
Given the table data below ("Table B"), it is a list of all stored users:
SERIALNO CONTID SYSNO AREA USRID
36 001 1 * 1
36 001 1 * 18
36 001 1 * 2
36 001 1 * 29
36 001 1 * 36
36 001 1 1 10
This table contains ALL users in the system.
How can I return all the users from Table B that have not been used for a given CONTID, SYSNO, and AREA?
For the first part of your question it would be as simples as a group by of a select on the desired fields:
SELECT SERIALNO,
SYSNO,
AREA,
USRNO,
MAX(EVDATE)
FROM CLOGS17
GROUP BY SERIALNO,
SYSNO,
AREA,
USRNO
Since you didn't provide enough information about the second part. This query will give you the output you show in your question.
So, to get all users that doesn't meet your 30 days criteria (whatever it are), you just do a left join of you user table with the above query seeking the nulls for the query above, like this:
SELECT *
FROM tableb tb LEFT JOIN
(SELECT SERIALNO,
SYSNO,
AREA,
USRNO,
MAX(EVDATE)
FROM CLOGS17
GROUP BY SERIALNO,
SYSNO,
AREA,
USRNO) a
ON tb.SERIALNO = a.SERIALNO,
AND tb.SYSNO = a.SYSNO
AND tb.USRNO = a.USRNO
WHERE a.AREA is null

SQL Server : query for DENSE_RANK() grouped by 2 column?

Need help in construct SQL, over an orders table, that holds the Date, SalesID, ItemID and other misc. columns.
Table looks like:
Date SalesID ItemID
13-9-15 6:15:00 56 6
13-9-15 6:00:00 56 6
13-9-15 6:26:00 56 4
13-9-15 6:38:00 34 4
13-9-15 7:05:00 34 2
13-9-15 6:42:00 12 2
13-9-15 7:20:00 12 5
13-9-15 7:34:00 78 5
13-9-15 7:41:00 78 6
What I'd like to have as an additional column is, one counter which is increments each time when new SalesID begins order by date.And the counter column will count until max no is 3.I'm using DENSE_RANK()for the increment column.
Finally what I need:
Date SalesID ItemID Counter
13-9-15 6:00:00 56 6 1
13-9-15 6:15:00 56 6 1
13-9-15 6:26:00 56 4 1
13-9-15 6:38:00 34 4 2
13-9-15 6:42:00 34 2 2
13-9-15 7:05:00 12 2 3
13-9-15 7:20:00 12 5 3
13-9-15 7:34:00 78 5 1
13-9-15 7:41:00 78 6 1
This solution works for sqlserver 2012+. I had to correct invalid data in your example in order to get the correct output
DECLARE #t table(Date datetime, SalesID int, ItemID int)
INSERT #t values
('2015-09-13 6:15:00',56,6),
('2015-09-13 6:00:00',56,6),
('2015-09-13 6:26:00',56,4),
('2015-09-13 6:38:00',34,4),
('2015-09-13 6:42:00',34,2),
('2015-09-13 7:05:00',12,2),
('2015-09-13 7:10:00',12,5),
('2015-09-13 7:34:00',78,5),
('2015-09-13 7:41:00',78,6)
;WITH CTE as
(
SELECT
[Date], [SalesID], [ItemID],
CASE WHEN lag(SalesID) over (order by Date) = SalesID
THEN 0 ELSE 1 END x
FROM #t
)
SELECT
[Date], [SalesID], [ItemID],
(sum(x) over (ORDER BY Date) - 1) % 3 + 1 [Counter]
FROM CTE
Result:
Date SalesID ItemID Counter
2015-09-13 06:00 56 6 1
2015-09-13 06:15 56 6 1
2015-09-13 06:26 56 4 1
2015-09-13 06:38 34 4 2
2015-09-13 06:42 34 2 2
2015-09-13 07:05 12 2 3
2015-09-13 07:10 12 5 3
2015-09-13 07:34 78 5 1
2015-09-13 07:41 78 6 1
This will work for sqlserver 2008:
;WITH CTE as
(
SELECT
[Date],
SalesID,
ItemID,
row_number() over (order by Date)-
row_number() over (partition by SalesID order by Date) x
FROM #t
)
SELECT
[Date],
SalesID,
ItemID,
(dense_rank() over (order by x) - 1) % 3 + 1 [Counter]
FROM CTE

SQL Server 2008 R2: Recursive query

This is the follow up question of : Prepare a recursive query
I have the table with the two columns namely cola and colb as shown below:
Table : Test
create table Test
(
cola int,
colb int
);
Records I have entered are:
Cola Colb
------------
1 2
1 3
1 4
2 5
2 6
2 3
3 2
3 4
3 7
3 10
10 11
11 12
11 13
11 14
12 15
13 16
14 99
15 88
16 77
Note: Now I want to show the only records who are connected with value I have pass. For example If I pass the value as 1 then it should display me the connected number to it and form connect like a tree.
For the above requirement I have got the script from Dark Knight as shown below which works fine.
;WITH CTE AS
(
SELECT COLA,COLB,','+CAST(COLA AS VARCHAR(MAX))+',' AS CHCK FROM test WHERE COLA=1
UNION ALL
SELECT C1.COLA,C1.COLB,C.CHCK+CAST(C1.cola AS VARCHAR(MAX))+','
FROM CTE C INNER JOIN test C1 ON C.colb = C1.cola
WHERE CHARINDEX(','+CAST(C.colb AS VARCHAR(MAX))+',',C.CHCK)=0
),
OUTERCTE AS
(
SELECT DISTINCT COLA,COLB,ROW_NUMBER() OVER(PARTITION BY Colb ORDER BY Cola) rn FROM CTE --ORDER BY COLA
)
SELECT Cola,Colb FROM OUTERCTE
WHERE rn<=1
ORDER BY CASE WHEN Cola = 1 THEN 1 ELSE 2 END;
Which gives me this:
----------------
Cola Colb
----------------
1 2
1 3
1 4
2 5
2 6
3 7
3 10
10 11
11 12
11 13
11 14
12 15
13 16
16 77
15 88
14 99
Requirement: Now I want to show the levels of records.
Expected Result:
------------------------------
Cola Colb Level
------------------------------
1 2 1
1 3 1
1 4 1
2 5 2
2 6 2
3 7 2
3 10 2
10 11 3
11 12 4
11 13 4
11 14 4
12 15 5
13 16 5
16 77 6
15 88 6
14 99 5
;WITH CTE AS
(
SELECT COLA,COLB
,','+CAST(COLA AS VARCHAR(MAX))+',' AS CHCK
, 1 as lvl FROM #Test WHERE COLA=1
UNION ALL
SELECT C1.COLA,C1.COLB ,C.CHCK+CAST(C1.cola AS VARCHAR(MAX))+','
, c.lvl+1
FROM CTE C INNER JOIN #Test C1 ON C.colb = C1.cola
WHERE CHARINDEX(','+CAST(C.colb AS VARCHAR(MAX))+',',C.CHCK)=0
),
cte2 as (
select * , ROW_NUMBER() over (partition by colb order by lvl)as rn From CTE
)
select cola,colb,lvl from cte2 where rn = 1

Reset a sum in a query when a date field changes month

I am currently executing the following query:
Select *, Balance = SUM(DailyReAdmits)
OVER (ORDER BY Date_Total ROWS UNBOUNDED PRECEDING)
From #AllReadmits
Which returns these results:
Date_Total DailyReAdmits Balance
2015-08-25 4 4
2015-08-26 8 12
2015-08-27 9 21
2015-08-28 3 24
2015-08-29 1 25
2015-08-30 4 29
2015-08-31 3 32
2015-09-01 5 37
However, when a new month starts, I would like the balance to start over again and look like this:
Date_Total DailyReAdmits Balance
2015-08-25 4 4
2015-08-26 8 12
2015-08-27 9 21
2015-08-28 3 24
2015-08-29 1 25
2015-08-30 4 29
2015-08-31 3 32
2015-09-01 5 5
How can I achieve this?
I supposed that you want partition by month, so try this:
SELECT *, Balance = SUM(DailyReAdmits)
OVER (PARTITION BY DATEPART(MM,Date_Total) ORDER BY Date_Total ROWS UNBOUNDED PRECEDING)
FROM #AllReadmits

Resources