Get two records per user id sql query - sql

I am getting data
1 34 abc5
1 24 abc3
1 12 abc2
1 24 abc1
1 34 abc6
1 34 abc76
1 24 ab1c243
1 24 abc243
1 34 abc243
1 34 abc243
from my query .. is there any way to get output like this
my query
SELECT * FROM table2
WHERE (abc2 IN (SELECT * FROM table3 AS f INNER JOIN
table1 AS u ON u.id_usr = f.userLogedin_id
WHERE (u.id_usr = '13'))) AND (publish_status = '3')
ORDER BY guser_ID
1 34 abc5
1 34 abc6
1 24 abc3
1 24 abc1
1 12 abc2
i.e. orderby desc and limit to 2 per unique user .. in this case 34, 24 and 12 are unique user

try this..
with cte as
(
select row_number() over (partition by <col2> order by <col2> desc) as id, col1,col2,col3 from <tablename>
)
select * from cte where id<=2

declare #t table (id int,value int,name varchar(10))
insert into #t (id,value,name)values (1,34,'abc5')
insert into #t (id,value,name)values (1,24,'abc3')
insert into #t (id,value,name)values (1,12,'abc2')
insert into #t (id,value,name)values (1,24,'abc1')
insert into #t (id,value,name)values (1,34,'abc6')
insert into #t (id,value,name)values (1,34,'abc76')
insert into #t (id,value,name)values (1,24,'ab1c243')
insert into #t (id,value,name)values (1,24,'abc243')
insert into #t (id,value,name)values (1,34,'abc243')
insert into #t (id,value,name)values (1,34,'abc243')
SELECT t.*
FROM (
SELECT DISTINCT value
FROM #t
) tt
CROSS APPLY
(
SELECT TOP 2 *
FROM #t t
WHERE t.value = tt.value
ORDER BY
1 DESC
) t

Related

Case when duplicate add one more letter

For example: I have a table with these records below
1 A
2 A
3 B
4 C
...
and I need to migrate these record in to another table
1 AA
2 AB
3 B
4 C
...
Meaning if the record is duplicate, it will automatically add one more letter alphabetically.
Just a slightly different approach
Example
Declare #YourTable Table (ID int,[SomeCol] varchar(50))
Insert Into #YourTable Values
(1,'A')
,(2,'A')
,(3,'B')
,(4,'C')
Select *
,NewVal = concat(SomeCol,IIF(sum(1) over (partition by SomeCol)=1,'',char(64+row_number() over ( partition by SomeCol order by ID ))) )
From #YourTable
Returns
ID SomeCol NewVal
1 A AA
2 A AB
3 B B
4 C C
EDIT - Requested UPDATE
Declare #YourTable Table (ID int,[SomeCol] varchar(50))
Insert Into #YourTable Values
(1,'A')
,(2,'A')
,(3,'B')
,(4,'C')
Select *
,NewVal = concat(SomeCol,IIF(sum(1) over (partition by SomeCol)=1,'',replace(char(63+row_number() over ( partition by SomeCol order by ID )),'#','')) )
From #YourTable
Returns
ID SomeCol NewVal
1 A A
2 A AA
3 B B
4 C C
We might be able to handle this requirement with the help of a calendar table mapping secondary letters to duplicate sequence counts:
WITH letters AS (
SELECT 1 AS seq, 'A' AS let UNION ALL
SELECT 2, 'B' UNION ALL
SELECT 3, 'C' UNION ALL
...
SELECT 26, 'Z' UNION ALL
...
),
cte AS (
SELECT id, let, ROW_NUMBER() OVER (PARTITION BY let ORDER BY id) rn,
COUNT(*) OVER (PARTITION BY let) cnt
FROM yourTable
)
SELECT t1.id, t1.let + CASE WHEN t1.cnt > 1 THEN t2.let ELSE '' END AS let
FROM cte t1
LEFT JOIN letters t2
ON t1.id = t2.seq
ORDER BY t1.id;
Demo

SQL count number of records where value remains constant

I need to find the count of tracker_id where position remains 1 through out the table.
tracker_id | position
---------------------
5 | 1
11 | 1
4 | 1
4 | 2
5 | 2
4 | 1
4 | 1
11 | 1
14 | 1
9 | 2
Here, the output should be 2 since, position of tracker_id:11 and 14 remains 1 through out the table.
You can use not exists
select count(*) from tbl a
where not exists(select 1
from tbl b
where a.tracker_id = b.tracker_id
and a.position <> b.position )
and a.position = 1
Output: 2
declare #table1 as table (tracker_id int,postion int)
insert into #table1 values (5,1)
insert into #table1 values (11,1)
insert into #table1 values (4,1)
insert into #table1 values (4,2)
insert into #table1 values (5,2)
insert into #table1 values (4,1)
insert into #table1 values (4,1)
insert into #table1 values (11,1)
insert into #table1 values (14,1)
insert into #table1 values (9,2)
select count(tracker_id),tracker_id,postion from #table1 group by tracker_id,postion
You can also do:
select ( count(distinct tracker_id) -
count(distinct tracker_id) filter (where position <> 1)
) as num_all_1s
from t;
Using uncorrelated subquery
select count(distinct tracker_id)
from t
where position=1
and tracker_id not in (select tracker_id from t where position<>1);
Using window function
select count(distinct tracker_id)
from (select *, avg(position) over (partition by tracker_id) as avg_pos from t) a
where avg_pos=1;
This one is just for giggles
select distinct count(*) over ()
from t
group by tracker_id
having count(*) = sum(position);
And if you really want to have fun
select count(distinct tracker_id)-count(distinct case when position<>1 then tracker_id end)
from t;
If position can only be 1, then you can use this, which gets all the tracker_ids with only a single position value, and then limits that to those records where position = 1:
WITH agg AS
(
SELECT
tracker_id
, p = MAX(position)
FROM table1
GROUP BY tracker_id
HAVING COUNT(DISTINCT position) = 1
)
SELECT COUNT(tracker_id)
FROM agg
WHERE p = 1

SQL Server 2008 Select all columns of a table + a column from the same table based on a column value

I have a table VERSION with composite keys docId, verId:
docId verId apprvDt old_verId
------ ------ ----------- ----------
A 3 03/20/2017 2
A 2 03/18/2017 1
A 1 03/16/2017 null
B 1 03/18/2017 null
C 2 03/20/2017 1
C 1 03/16/2017 null
Say I select docId=A, verId=3, query should return
docId verId apprvDt old_verId old_apprvDt
------ ------ ----------- ---------- ------------
A 3 03/20/2017 2 03/18/2017
that is to retrieve the apprvDt of the old_verId.
I tried like this
select a.docId, a.verId, a.apprvDt, a.old_verId, b.old_apprvDt
from VERSION as a left join
(select x.docId, x.verId, x.apprvDt as old_apprvDt from REVISN as x
where x.docId = 'A' and x.verId = a.old_verId) as b
on b.docId = a.docId and b.verId = a.old_verId
but I am getting a multi-part binding error.
I want to select a row from VERSION including the apprvDt (old_apprvDt) of old_verId
Solution to your problem is as given below :
DECLARE #tbl TABLE(docId varchar(100), verId int, apprvDt datetime, old_verId int)
insert into #tbl values('A', 3 , '03/20/2017', 2)
insert into #tbl values('A', 2 , '03/18/2017', 1)
insert into #tbl values('A', 1 , '03/16/2017', NULL)
insert into #tbl values('B', 1 , '03/18/2017', NULL)
insert into #tbl values('C', 2 , '03/20/2017', 1)
insert into #tbl values('C', 1 , '03/16/2017', NULL)
select * from #tbl
;with data_table
as
(
select docId,verId,apprvDt,old_verId,
(select apprvDt from #tbl T2 where T2.docId=t1.docid and T2.verId=t1.old_verId)
old_apprvDt from #tbl t1
)
select * from data_table where docId='A' and verId=3
Result is as below :
-------------------------------------------------------------------------------------
docId verId apprvDt old_verId old_apprvDt
-------------------------------------------------------------------------------------
A 3 2017-03-20 00:00:00.000 2 2017-03-18 00:00:00.000
select t1.*,
b.apprvdt as old_apprvdt
from table1 t1
cross apply
(
select apprvdt from table1 t2 where t1.docid=t2.docid
and t2.old_verid =t1.verid ) b

Select 30% of each column value

Let's assume we have a table with a column 'A' that has values from 0 to N. And I want to select 30% each rows that have the same value for the column 'A'.
So if I have this:
A| B
-------
0 hello
0 test
0 hi
1 blah1
1 blah2
1 blah3
1 blah4
1 blah5
1 blah6
Result:
A| B
-------
0 hello
1 blah1
1 blah4
it could be blah1 or any other blah that is not blah4, and blah4 can be any other blah that is not blah1, basically it could be random or skipping.
By the way, the actual table is huge, talking terabytes, so think about performance.
try something like this:
DECLARE #YourTable table (A int, b varchar(10))
INSERT #YourTable VALUES (0, 'hello') --OP's data
INSERT #YourTable VALUES (0, 'test')
INSERT #YourTable VALUES (0, 'hi')
INSERT #YourTable VALUES (1, 'blah1')
INSERT #YourTable VALUES (1, 'blah2')
INSERT #YourTable VALUES (1, 'blah3')
INSERT #YourTable VALUES (1, 'blah4')
INSERT #YourTable VALUES (1, 'blah5')
INSERT #YourTable VALUES (1, 'blah6')
;WITH NumberedRows AS
( SELECT
A,B,ROW_NUMBER() OVER (PARTITION BY A ORDER BY A,B) AS RowNumber
FROM #YourTable
)
, GroupCounts AS
( SELECT
A,MAX(RowNumber) AS MaxA
FROM NumberedRows
GROUP BY A
)
SELECT
n.a,n.b
FROM NumberedRows n
INNER JOIN GroupCounts c ON n.A=c.A
WHERE n.RowNUmber<=(c.MaxA+1)*0.3
OUTPUT:
a b
----------- ----------
0 hello
1 blah1
1 blah2
(3 row(s) affected)
EDIT based on the great idea in the comment from Andriy M
;WITH NumberedRows AS
( SELECT
A,B,ROW_NUMBER() OVER (PARTITION BY A ORDER BY A,B) AS RowNumber
,COUNT(*) OVER (PARTITION BY A) AS TotalOf
FROM #YourTable
)
SELECT
n.a,n.b
FROM NumberedRows n
WHERE n.RowNumber<=(n.TotalOf+1)*0.3
ORDER BY A
OUTPUT:
a b
----------- ----------
0 hello
1 blah1
1 blah2
(3 row(s) affected)
EDIT here are "random" rows, using Andriy M idea:
DECLARE #YourTable table (A int, b varchar(10))
INSERT #YourTable VALUES (0, 'hello') --OP's data
INSERT #YourTable VALUES (0, 'test')
INSERT #YourTable VALUES (0, 'hi')
INSERT #YourTable VALUES (1, 'blah1')
INSERT #YourTable VALUES (1, 'blah2')
INSERT #YourTable VALUES (1, 'blah3')
INSERT #YourTable VALUES (1, 'blah4')
INSERT #YourTable VALUES (1, 'blah5')
INSERT #YourTable VALUES (1, 'blah6')
;WITH NumberedRows AS
( SELECT
A,B,ROW_NUMBER() OVER (PARTITION BY A ORDER BY newid()) AS RowNumber
FROM #YourTable
)
, GroupCounts AS (SELECT A,COUNT(A) AS MaxA FROM NumberedRows GROUP BY A)
SELECT
n.A,n.B
FROM NumberedRows n
INNER JOIN GroupCounts c ON n.A=c.A
WHERE n.RowNUmber<=(c.MaxA+1)*0.3
ORDER BY n.A
OUTPUT:
a b
----------- ----------
0 hi
1 blah3
1 blah6
(3 row(s) affected)
This uses only one subquery, and thus a single pass through your set.
SELECT a
, b
FROM
(
SELECT A
, b
, ROW_NUMBER()
OVER( PARTITION BY A
ORDER BY b
) r
, COUNT(b)
OVER( PARTITION BY A
) ct
FROM #YourTable
) n
WHERE n.r <= n.ct * 0.3
As does this, although this always returns the top 3 if there are fewer than 10 and "extras" get posted to the first bins.:
SELECT A
, b
FROM
(
SELECT A
, b
, NTILE(10)
OVER( PARTITION BY a
ORDER BY b
) tens
FROM #YourTable
) n
WHERE tens <= 3;

Order by specific values in a column without using case statement

I would like to get the records in the below format:
if i have a record like
A, B, C, D
and I would like get record in this order -
B, A, C, D, E, F, G, H, so on,
But I need the value B should be at the first row...
try this:
SELECT
*, 1 AS SortBy
FROM YourTable
WHERE YourCol='B'
UNION ALL
SELECT
*, 2 AS SortBy
FROM YourTable
WHERE YourCol!='B'
ORDER BY SortBy, YourCol
You don't give any reason to not want to use CASE. I'd still give it a try and see which is faster, the UNION ALL or the CASE method:
SELECT
*
FROM YourTable
ORDER BY CASE WHEN YourCol='B' then 1 ELSE 2 END, YourCol
EDIT Working example:
DECLARE #YourTable table (YourCol char(1), RowValue varchar(5))
INSERT #YourTable VALUES ('A','aaa')
INSERT #YourTable VALUES ('A','aa')
INSERT #YourTable VALUES ('B','bbb')
INSERT #YourTable VALUES ('B','bb')
INSERT #YourTable VALUES ('C','ccc')
INSERT #YourTable VALUES ('D','ddd')
INSERT #YourTable VALUES ('E','eee')
INSERT #YourTable VALUES ('F','fff')
SELECT
*, 1 AS SortBy
FROM #YourTable
WHERE YourCol='B'
UNION ALL
SELECT
*, 2 AS SortBy
FROM #YourTable
WHERE YourCol!='B'
ORDER BY SortBy, YourCol
OUTPUT:
YourCol RowValue SortBy
------- -------- -----------
B bbb 1
B bb 1
A aaa 2
A aa 2
C ccc 2
D ddd 2
E eee 2
F fff 2
(8 row(s) affected)
SELECT * from mytable where mycolumn = "B";
followed by
SELECT * from mytable where mycolumn != "B" order by mycolumn asc;
Declare and populate table:
DECLARE #t TABLE (col1 CHAR)
INSERT #t
SELECT char(number+ 65)
FROM master..spt_values
WHERE type = 'P' AND number < 6
Query1:
SELECT *, cast(ascii(col1)-66 as bit) * 2 + ascii(col1) [orderby]
FROM #t
ORDER BY cast(ascii(col1)-66 as bit) * 2 + ascii(col1)
Query2:
SELECT *
FROM #t
ORDER BY replace(col1, 'B', ' ')
Result for Query1: (the [orderby] column is included for documentation only)
col1 orderby
---- --------
B 66
A 67
C 69
D 70
E 71
F 72