Given this table:
id
Name
date
21
B1
2022-02-26
21
B
2022-02-26
01
C1
2022-02-26
04
T1
2022-02-16
04
T
2022-02-16
PS: This table is the result of join request.
I want to select the rows with corrurent day where Id doesn't repeated like:
id
Name
date
01
C1
2022-02-26
How I can do that with SQL query please.
DB
CREATE TABLE test (
id INT,
name CHAR,
date DATE
);
INSERT INTO test VALUES (1, 'A', '2022-02-22');
INSERT INTO test VALUES (1, 'B', '2022-02-21');
INSERT INTO test VALUES (2, 'C', '2022-02-20');
INSERT INTO test VALUES (3, 'D', '2022-02-19');
QUERY
select * from test
where id in (select id from test group by id having count(*) = 1)
OUTPUT
id name date
2 C 2022-02-20
3 D 2022-02-19
db-fiddle
with cte as
(
select id, count(Name) as cnt
from TableName
group by id
)
select cte.id, tableName.Name
from cte
inner join TableName on
cte.id = tableName.id
where cte.cnt = 1
select id,name from test
where ID NOT IN ( select id from test group by id having count(*)> 1)
select * from test where id not in
(select distinct id from
(select *,row_number ()
over (partition by id order by Name asc) rn
from test
) b
where rn>1)
Assuming the table name is Test. The below query would work.
Select *
From Test
Group by Id
Having count(*) = 1
The most efficient way to do this is likely to be using window functions to check if there is another row
SELECT *
FROM (
SELECT *,
LEAD(id) OVER (PARTITION BY id ORDER BY Name) rn
FROM YourTable t
) t
WHERE t.nxt IS NULL;
Related
I have a list like this example:
abc, efg, rty
and a table with following data:
1 abcd
2 efgh
3 abcd
4 rtyu
5 efgh
now I want to find the first-row which start with list item in the table. my expected result is:
1 abcd
2 efgh
4 rtyu
This is a complete script to do the job
Declare #v_List Table
(
Text nvarchar(100)
)
Declare #v_Data Table
(
Number int,
Text nvarchar(100)
)
Insert Into #v_List values(N'abc')
Insert Into #v_List values(N'efg')
Insert Into #v_List values(N'rty')
Insert Into #v_Data values(1, N'abcd')
Insert Into #v_Data values(2, N'efgh')
Insert Into #v_Data values(3, N'abcd')
Insert Into #v_Data values(4, N'rtyu')
Insert Into #v_Data values(5, N'efgh')
;with CTE as
(
Select D.Number,
D.Text,
ROW_NUMBER() OVER (PARTITION BY L.Text Order By D.Number) as Row_No
From #v_Data D
Join #v_List L
On D.Text like L.Text + '%'
)
Select CTE.Number,
CTE.Text
From CTE
Where CTE.Row_No = 1
select * from TableName
where Id in
(
select min(Id) from
(
select Id,
case
when Val like 'abc%' then 1
when Val like 'efg%' then 2
when Val like 'rty%' then 3
else 0 end temp
from TableName
)t where temp > 0
group by temp
)
You can use a windowed ROW_NUMBER to generate a sequential number by each different value, then just display the first one only.
;WITH RowNumbersByValue AS
(
SELECT
T.ID,
T.Value,
RowNumber = ROW_NUMBER() OVER (PARTITION BY T.Value ORDER BY T.ID)
FROM
YourTable AS T
)
SELECT
R.ID,
R.Value
FROM
RowNumbersByValue AS R
WHERE
R.Value IN ('abcd', 'efgh', 'rtyu') AND
R.RowNumber = 1
For SQL Server I prefer this version, which does not require a subquery:
SELECT TOP 1 WITH TIES ID, Value
FROM yourTable
WHERE Value LIKE 'abc%' OR Value LIKE 'efg%' OR Value LIKE 'rty%'
ORDER BY ROW_NUMBER() OVER (PARTITION BY Value ORDER BY ID);
SELECT * INTO #temp FROM (VALUES
(1 ,'abcd'),
(2 ,'efgh'),
(3 ,'abcd'),
(4 ,'rtyu'),
(5 ,'efgh'))a([id], [name])
You can use min and group by function
SELECT MIN(id), name FROM #temp GROUP BY name
You may use this, there are so many ways to achieve this, use whichever suits you better.
using subquery
select id, col from
(select Row_number() over (partition by col order by id) as slno, id, col from yourtable)
as tb where tb.slno=1
using cte
; with cte as (
select row_number() over (partition by col order by id) as Slno, id, col from table)
select id, col from cte where slno=1
using min
select Min(id) , col from table group by col
Note:-
In the end of any above mentioned query you may apply your where clause to filter your records as needed.
create Table A
(
ID Int,
Name Varchar(10)
)
Insert Into A Values(1,'A'),
(1,'B'),
(2,'A'),
(3,'A'),
(3,'C'),
(2,'B'),
(2,'C'),
(1,'C'),
(4,'C'),
(4,'B')
SELECT * FROM A ORDER BY NAME,ID
Result:
ID Name
1 A
2 A
3 A
1 B
2 B
4 B
1 C
2 C
3 C
4 C
If I run this below query:
;WITH CTETEST
AS
(
SELECT MAX(ID)[MAXID],Name FROM A GROUP BY NAME
)
SELECT max([MAXID])[ID],A.Name FROM CTETEST
join A
on A.ID=CTETEST.MAXID
GROUP BY A.NAME
Result:
ID Name
3 A
4 B
4 C
I want this above result set in the main base table and delete rest which is less then the highest ID under each Name category. Please suggest me some query.
I would use an updatable CTE in SQL Server:
with todelete as (
select a.*, max(id) over (partition by name) as maxid
from a
)
delete todelete from todelete
where id < maxid;
In almost any database, you can use:
delete a
where id < (select max(id) from a a2 where a2.name = a.name);
You can try to delete by CTE, make row number by Name order by ID desc in CTE.
Then only keep rn = 1 row datas.
;with cte as(
SELECT *,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY ID desc) rn FROM A
)
delete cte
where rn > 1
sqlfiddle
I have a patients table with details such as conditions that the patient has. from the below table I want to select Patients, Claims which have ONLY a single condition - 'Hypertension'. Example Patient B is the expected output. Patient A will not be selected because he claimed for multiple conditions.
+----+---------+--------------+
| ID | ClaimID | Condition |
+----+---------+--------------+
| A | 14234 | Hypertension |
| A | 14234 | Diabetes |
| A | 63947 | Diabetes |
| B | 23853 | Hypertension |
+----+---------+--------------+
I tried using the NOT IN condition as below but doesn't seem to help
SELECT ID, ClaimID, Condition
FROM myTable
WHERE Condition IN ('Hypertension')
AND Condition NOT IN ('Diabetes')
One method uses not exists:
select t.*
from mytable t
where t.condition = 'Hypertension' and
not exists (select 1
from mytable t2
where t2.id = t.id and t2.condition <> t.condition
);
Or you can do it like this:
select
id,
claim_id,
condition
from
patient
where
id in
(
select
id
from
patient
group by
id having count (distinct condition) = 1
);
Result:
id claim_id condition
-- ----------- ----------------
B 23853 Hypertension
(1 rows affected)
Setup:
create table patient
(
id varchar(1),
claim_id int,
condition varchar(16)
);
insert into patient (id, claim_id, condition) values ('A', 14234, 'Hypertension');
insert into patient (id, claim_id, condition) values ('A', 14234, 'Diabetes');
insert into patient (id, claim_id, condition) values ('A', 63947, 'Diabetes');
insert into patient (id, claim_id, condition) values ('B', 23853, 'Hypertension');
You can do this with a CTE.
I set up this CTE with two parameters, one being the Condition you seek, and the other being the max number of combined conditions to find (in your case 1).
DECLARE #myTable TABLE (Id VARCHAR(1), ClaimID INT, Condition VARCHAR(100))
INSERT INTO #myTable (Id, ClaimID, Condition)
SELECT 'A',14234,'Hypertension' UNION ALL
SELECT 'A',14234,'Diabetes' UNION ALL
SELECT 'A',63947,'Diabetes' UNION ALL
SELECT 'B',23853,'Hypertension'
DECLARE #Condition VARCHAR(100)
DECLARE #MaxConditions TINYINT
SET #Condition='Hypertension'
SET #MaxConditions=1
; WITH CTE AS
(
SELECT *, COUNT(2) OVER(PARTITION BY ClaimID) AS CN
FROM #myTable T1
WHERE EXISTS (SELECT 1 FROM #myTable T2 WHERE T1.ClaimID=T2.ClaimID AND T2.Condition=#Condition)
)
SELECT *
FROM CTE
WHERE CN<=#MaxConditions
If you don't care about the fluff, and just want all ClaimID's with just ONE condition regardless of which condition it is use this.
DECLARE #myTable TABLE (Id VARCHAR(1), ClaimID INT, Condition VARCHAR(100))
INSERT INTO #myTable (Id, ClaimID, Condition)
SELECT 'A',14234,'Hypertension' UNION ALL
SELECT 'A',14234,'Diabetes' UNION ALL
SELECT 'A',63947,'Diabetes' UNION ALL
SELECT 'B',23853,'Hypertension'
DECLARE #MaxConditions TINYINT
SET #MaxConditions=1
; WITH CTE AS
(
SELECT *, COUNT(2) OVER(PARTITION BY ClaimID) AS CN
FROM #myTable T1
)
SELECT *
FROM CTE
WHERE CN<=#MaxConditions
Here is one method using Having clause
SELECT t.*
FROM mytable t
WHERE EXISTS (SELECT 1
FROM mytable t2
WHERE t2.id = t.id
HAVING Count(CASE WHEN condition = 'Hypertension' THEN 1 END) > 0
AND Count(CASE WHEN condition != 'Hypertension' THEN 1 END) = 0)
And yet a couple of other ways to do this:
declare #TableA table(Id char,
ClaimId int,
Condition varchar(250));
insert into #TableA (id, claimid, condition)
values ('A', 14234, 'Hypertension'),
('A', 14234, 'Diabetes'),
('A', 63947, 'Diabetes'),
('B', 23853, 'Hypertension')
select id, claimid, condition
from #TableA a
where not exists(select id
from #TableA b
where a.id = b.id
group by b.id
having count(b.id) > 1)
OR
;with cte as
(
select id, claimid, condition
from #TableA
)
,
cte2 as
(
Select id, count(Id) as counts
from cte
group by id
having count(id) < 2
)
Select cte.id, claimid, condition
From cte
inner join
cte2
on cte.id = cte2.id
I decided to revise my answer into an appropriate one.
A simple solution to your question is to count the rows instead of the ID values (since it's not an integer).
Here is a simple introduction:
SELECT
ID
FROM
#PatientTable
GROUP BY
ID
HAVING
ID = ID AND COUNT(*) = 1
This will Return the ID B
+----+
| ID |
+----+
| B |
+----+
Surely, this is not enough, as you may work with a large data and need more filtering.
So, we will go and use it as a sub-query.
Using it as a sub-query it's simple :
SELECT
ID,
ClaimID,
Condition
FROM
#PatientTable
WHERE
ID = (SELECT ID AS NumberOfClaims FROM #PatientTable GROUP BY ID HAVING ID = ID AND COUNT(*) = 1)
This will return
+----+---------+--------------+
| ID | ClaimID | Condition |
+----+---------+--------------+
| B | 23853 | Hypertension |
+----+---------+--------------+
So far so good, but there is another issue we may face. Let's say you have a multiple Claims from a multiple patients, using this query as is will only show one patient. To show all patients we need to use IN rather than = under the WHERE clause
WHERE
ID IN (SELECT ID AS NumberOfClaims FROM #PatientTable GROUP BY ID HAVING ID = ID AND COUNT(*) = 1)
This will list all patients that falls under this condition.
If you need more conditions to filter, you just add them to the WHERE clause and you'll be good to go.
SELECT id, sum(ct)
FROM (SELECT customer_id, CASE WHEN category = 'X' THEN 0 else 1
end ct
FROM MASTER_TABLE
) AS t1
GROUP BY id
HAVING sum(ct) = 0
id which will have sum(ct) more than 1, will have multiple conditions
Use joins instead of subquery. Joins are always better in performance. You can use below query.
SELECT T1.id, T1.claimid, T1.Condition
FROM mytable T1
INNER JOIN
(
select id, count(Condition) counter
from mytable
group by id HAVING COUNT(DISTINCT CONDITION)=1
) T2 ON T1.ID=T2.ID
WHERE T2.counter=1
I got that table :
id table_id ....
1 1
2 1
3 1
4 2
5 2
I want a query to get top record from all who have the same table_id
Result :
id table_id ....
1 1
4 2
I tried :
SELECT
id, shift_id, name_of_shift, person_in_shift,
starttime_in_shift, endtime_in_shift, table_id,
startdate, enddate, point_id
FROM
sarcshifttable
WHERE
(table_id IN (SELECT DISTINCT table_id
FROM sarcshifttable AS sarcshifttable_1))
but its bring me all the data and I want just the top one
He said he wanted all the columns back, so it will have to be this:
SELECT
id, shift_id, name_of_shift, person_in_shift,
starttime_in_shift, endtime_in_shift, table_id,
startdate, enddate, point_id
FROM
sarcshifttable
WHERE id IN
(
SELECT MIN(id)
FROM sarcshifttable
GROUP BY table_id
)
SELECT * FROM Table
WHERE ID IN
(SELECT ID FROM ( SELECT MIN(ID)as ID,table_id FROM Table GROUP BY table_id)x)
They're right - by selecting the lowest (MIN()) ID grouping by table_id, you can find out the earliest row for that particular table ID.
Something like this:
SELECT
MIN(id), table_id
FROM
table1
GROUP BY
table_id
Update:
Better understanding the request, the following SQL will work:
SELECT
id, shift_id, name_of_shift, person_in_shift,
starttime_in_shift, endtime_in_shift, table_id,
startdate, enddate, point_id
FROM
table1
WHERE
id IN (
SELECT MIN(ID)
FROM table1 GROUP BY table_id
)
A working example (updated) can be seen here at SQLFiddle.
DECLARE #What TABLE
(
id INT,
tableId INT
)
INSERT INTO #What
VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 2),
(5, 2)
SELECT a.id, a.tableId
FROM
(
SELECT id, tableId, Rank() OVER (PARTITION BY tableId ORDER BY id) localRank
FROM #What
) a
WHERE a.localRank = 1
ORDER BY a.id
id tableId
1 1
4 2
I want to create a table with a subset of records from a master table.
for example, i have:
id name code
1 peter 73
2 carl 84
3 jack 73
I want to store peter and carl but not jack because has same peter's code.
I need hight performance because i have 20M records.
I try this:
SELECT id, name, DISTINCT(code) INTO new_tab
FROM old_tab
WHERE (conditions)
but don't work.
Assuming you want to pick the row with the maximum id per code, then this should do it:
insert into new_tab (id, name, code)
(SELECT id, name, code
FROM
(
SELECT id, name, code, rank() as rnk OVER (PARTITION BY code ORDER BY id DESC)
FROM old_tab WHERE rnk = 1
)
)
and for the minimum id per code, just change the sort order in the rank from DESC to ASC:
insert into new_tab (id, name, code)
(SELECT id, name, code
FROM
(
SELECT id, name, code, rank() as rnk OVER (PARTITION BY code ORDER BY id ASC)
FROM old_tab WHERE rnk = 1
)
)
Using a derived table, you can find the minID for each code, then join back to that in the outer to get the rest of the columns for that ID from oldTab.
select id,name,code
insert into newTabFROM
from old_tab t inner join
(SELECT min(id) as minId, code
from old_tab group by code) x
on t.id = x.minId
WHERE (conditions)
Try this:
CREATE TABLE #Temp
(
ID INT,
Name VARCHAR(50),
Code INT
)
INSERT #Temp VALUES (1, 'Peter', 73)
INSERT #Temp VALUES (2, 'Carl', 84)
INSERT #Temp VALUES (3, 'Jack', 73)
SELECT t2.ID, t2.Name, t2.Code
FROM #Temp t2
JOIN (
SELECT t.Code, MIN(t.ID) ID
FROM #temp t
JOIN (
SELECT DISTINCT Code
FROM #Temp
) d
ON t.Code = d.Code
GROUP BY t.Code
) b
ON t2.ID = b.ID