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
Related
This is one of my views called xyz:
ID | NAME |......Other Data... | Marks
1 A 100
1 A 100
1 A 99
1 A 95
1 A 94
1 A 94
1 A 94
1 A 91
1 A 87
1 A 86
2 B 100
2 B 94
2 B 93
2 B 90
2 B 89
2 B 89
2 B 87
2 B 86
3 C 100
3 C 98
3 C 98
3 C 97
3 C 92
3 C 91
3 C 90
The query I used to get this is something like this:
create or replace view xyz as
select *
from abc
where id in
(select id
from data)
order by id, mark desc, id;
And based on unique ids I want the top 5 rows:
ID | NAME |......Other Data... | Marks
1 A 100
1 A 100
1 A 99
1 A 95
1 A 94
2 B 100
2 B 94
2 B 93
2 B 90
2 B 89
3 C 100
3 C 98
3 C 98
3 C 97
3 C 92
I tried referring to this:
MySQL: Select top 5 rows based on ID and find Subtotal
But I wasn't able to do it. Could you please help?
You can use a windowed rank(), partitioned by each student name, and ordered by marks descending, to find the top 5 marks for each Student:
WITH cteRankedMarks AS
(
SELECT "ID", "NAME", "Marks",
rank() OVER (PARTITION BY "NAME"
ORDER BY "Marks" DESC) AS rank
FROM MyTable
)
SELECT "ID", "NAME", "Marks"
FROM cteRankedMarks
WHERE rank <= 5
ORDER BY "NAME", "Marks" DESC;
SqlFiddle here
Notes
If two or more marks have the same value vying for 5th place, then , then rank will return all such marks. If you don't want ties, then use row_number() instead of rank(). More about these here
Obviously, if a student doesn't have 5 marks, then fewer rows will be returned.
I'm having two table which contain data for reviler for employee on shift basis
e.g
Table 1
------
ID NAME RELIVERID
------------
20 ABC 56
----------
21 XYZ 57
----------
22 DEF 58
----------
TABLE 2
---------
ID NAME RELIVERID
-------
56 PQR 20
-----
57 STU 21
-----
58 XYZ 21
----
I want result in third table with following data
Result Table
-------
ID NAME RELIVERID
---
20 ABC 56
-
56 PQR 20
-
21 XYZ 57
-
57 STU 21
-
22 DEF 58
-
58 XYZ 21
-
1 row from first table and alternate row from second table
My suggestion is to use the row_number function, multiply it with a factor for the 1st table and for the second table add 1 so it will be greater than the one in the 1st table and perform an union all. I don't a SQL Server instance to test this, but it should be something like this:
SELECT (ROW_NUMBER() OVER (ORDER BY ID ASC)) * 100 AS OrderID, * FROM Table1
UNION ALL
SELECT (ROW_NUMBER() OVER (ORDER BY ID ASC)) * 100 + 1 AS OrderID, * FROM Table2
ORDER BY OrderID
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
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
I have tables
table1
epid etid id EValue reqdate
----------- ----------- ----------- ------------ ----------
15 1 1 498925307069 2012-01-01
185 1 2 A5973FC43CE3 2012-04-04
186 1 2 44C6A4B776A2 2012-04-05
205 1 2 7A0ED3F1DA13 2012-09-19
206 1 2 77771D65F9C4 2012-09-19
207 1 2 AD74A4AA41BD 2012-09-19
208 1 2 9595ABE5A0C8 2012-09-19
209 1 2 7611D2FB395B 2012-09-19
210 1 2 04A510D6067A 2012-09-19
211 1 2 24D43EC268F8 2012-09-19
table2
PEId Id EPId
----------- ----------- -----------
43 9 15
44 10 15
45 11 15
46 12 15
47 13 15
48 14 15
49 15 15
50 16 15
51 17 15
52 18 15
table3
PLId PEId Id ToPayId
----------- ----------- ----------- -----------
71 43 9 1
72 43 9 2
73 44 10 1
74 44 10 2
75 45 11 1
76 45 11 2
77 46 12 1
78 46 12 2
79 47 13 1
80 47 13 2
I want to get one id whose count is less than 8 in table 3 and order by peid in table 2,
I have written query
SELECT Top 1 ToPayId FROM
(
SELECT Count(pl.ToPayId) C, pl.ToPayId
FROM table3 pl
INNER JOIN table2 pe ON pl.peid = pe.peid
INNER JOIN table1 e ON pe.epid = e.epid
WHERE e.EtId=1 GROUP BY pl.ToPayId
) As T
INNER JOIN table2 p ON T.ToPayId= p.Id
WHERE C < 8 ORDER BY p.PEId ASC
This query executes more than 1000 times in stored procedure depends on the entries in user-defined-table-type using while condition.
But it is very slow as we have millions of entries in each table.
Can anyone suggest better query regarding above?
maybe try with the having clause to get rid of the from select
select table2.id as due
from table3 inner join table2 on table2.PEId=table3.PEId...
group by ...
having count(due) <8
order by ...
-> you have a redundant Id column in table3 : seems pretty useless as the couple PEId and Id appears unique so remove it and reduce the size of table 3 by 25% hence improving performance of db
Will.. since you did not provide enough sample data and I am not sure what exactly your business logic is. So that I can just modify the code in blind.
SELECT ToPayId
FROM (
SELECT TOP 1 Count(pl.ToPayId) C, pl.ToPayId, pe.PEId
FROM table3 as pl
INNER JOIN table2 as pe ON pl.peid = pe.peid AND pl.ToPayId = pe.Id
INNER JOIN table1 e ON pe.epid = e.epid
WHERE e.EtId=1
GROUP BY pl.ToPayId, pe.PEId
HAVING Count(pl.ToPayId) < 8
ORDER BY pe.PEId ASC
) AS T