Select rows with same ID/email but different value in other table - sql

Select rows with same ID/email but different value in other table
I have two tables: person and email, now there are mail addresses that have the same value, and persons/ID with different values.
Can anyone tell how to write an SQL query for this? I have tried but I can't figure it out. I have found some answers but then it is always finding the match in the same table
Like this
Table_person. ​​Table_email
1​​​ email#persoon1
2​​​ email#persoon2
3​​​ email#persoon3
4​​​ email#persoon1
5​​​ email#persoon5
6​​​ email#persoon2
The output should be
Table_person​​ Table_email
1​​​ email#persoon1
4​​​ email#persoon1
2​​​ email#persoon2
6​​​ email#persoon2

Using a common table expression with row_number()
;with cte as (
select *
, rn = row_number() over (partition by email order by person_id)
from email e
)
select *
from cte
where exists (
select 1
from cte i
where i.email = cte.email
and rn > 1
)
or using exists()
select *
from email e
where exists (
select 1
from email i
where i.email = e.email
and i.person_id <> e.person_id
)
rextester demo: http://rextester.com/JHFEF82373

Hope it will helps you
;with cte(Table_person,​​Table_email)
AS
(
SELECT 1​​​,'email#persoon1' UNION ALL
SELECT 2​​​,'email#persoon2' UNION ALL
SELECT 3​​​,'email#persoon3' UNION ALL
SELECT 4​​​,'email#persoon1' UNION ALL
SELECT 5​​​,'email#persoon5' UNION ALL
SELECT 6​​​,'email#persoon2'
)
,Cte2
AS
(
SELECT Table_person,​​Table_email From
(
Select Table_person,​​Table_email,ROW_NUMBER()OVER(Partition by Table_email Order By Table_person )Seq
from cte
)dt WHERE dt.Seq>1
)
,Final
AS
(
SELECT Table_person,​​Table_email From
(
Select Table_person,​​Table_email,ROW_NUMBER()OVER(Partition by Table_email Order By Table_email )Seq2
from cte
)dt
where dt.Seq2>1
Union ALL
SELECT Table_person,​​Table_email From cte2
)
SELECt Table_person,​​Table_email from Final

Related

Fetch rows with same id and different prod_id

I have two tables: tbltest1 and tbltest2
I want all the distinct rows of both tables, except the ones that have null in prod_id unless there is not any row in both tables with the same id with a not null prod_id
I tried to make a set with all the values then DISTINCTed to take only the unique ones and after used ROWNUMBER() OVER().:
with p as(
select t.*
from tbltest1 as t
union all
select d.*
from tbltest2 as d
),
s as (
select distinct colb, num,
ROW_NUMBER() OVER (PARTITION BY num ORDER BY colb DESC) as rnk
from p
)select *
from s
where rnk = 1
How can I achieve that? Is there also any other more efficient way to do it instead of this logic?
Use UNION for the 2 tables to remove the duplicates (if any) and then NOT EXISTS:
WITH cte AS (
SELECT prod_id, dn FROM tbltest2
UNION
SELECT prod_id1, dn1 FROM tbltest1
)
SELECT c1.*
FROM cte c1
WHERE c1.prod_id IS NOT NULL
OR NOT EXISTS (SELECT 1 FROM cte c2 WHERE c2.dn = c1.dn AND c2.prod_id IS NOT NULL)
See the demo.

Recursive CTE to find present and previous WorkState and entry time of the WorkState

I have the below
The schema is as under
declare #t table(CustomerId varchar(10),WorkState varchar(10),statechangedate datetimeoffset, stateorder int)
insert into #t
select '1','WorkStateA','2018-10-30 13:38:53.5133333 +00:00',1 union all
select '2','WorkStateA','2018-05-18 17:04:56.9900000 +00:00',1 union all
select '2','WorkStateA','2018-05-18 16:22:20.3266667 +00:00',2 union all
select '2','WorkStateB','2018-05-09 12:46:33.8300000 +00:00',3 union all
select '3','WorkStateF','2018-06-21 12:40:03.2933333 +00:00',1 union all
select '3','WorkStateE','2018-06-21 12:38:43.9000000 +00:00',2 union all
select '3','WorkStateD','2018-06-21 12:38:24.7533333 +00:00',3 union all
select '3','WorkStateC','2018-06-21 12:38:11.0233333 +00:00',4 union all
select '3','WorkStateB','2018-06-21 12:38:04.1933333 +00:00',5 union all
select '3','WorkStateA','2018-06-21 12:36:51.4633333 +00:00',6
select * from #t
What I am looking for
Means I need to capture the Present and Previous WorkState and Entry time of the WorkState on customer basis.
I have tried with the below recursive CTE
;with cte as(
select
t.CustomerId,
PresentWorkState = t.WorkState,
PresentStatechangedate = t.statechangedate,
t.stateorder,
PreviousWorkState = null ,
PreviousStatechangedate= null
from #t t where t.stateorder=1
union all
select
t1.CustomerId,
t1.WorkState,
t1.statechangedate,
c.stateorder,
c.PreviousWorkState,
c.PreviousStatechangedate
from #t t1
join cte c on t1.stateorder !=c.stateorder)
select *
from cte
but could not.
Like Andrew said LAG() should work for your purpose instead of using recursive cte. Check this:
SELECT *
,LAG(WorkState) OVER(PARTITION BY CustomerId ORDER BY statechangedate)
,LAG(statechangedate) OVER(PARTITION BY CustomerId ORDER BY statechangedate)
FROM #T
ORDER BY CustomerId,statechangedate
(Posted on behalf of the question author).
LEAD function solved it. Here is the output:
select
CustomerId,
PresentWorkState = WorkState,
PresentStatechangedate = statechangedate,
PreviousWorkState = LEAD(WorkState) OVER (partition by CustomerId ORDER BY stateorder) ,
PreviousStatechangedate = LAG(statechangedate) OVER (partition by CustomerId ORDER BY stateorder)
from #t

How to use Dynamic Lag function to avoid joining a table to itself to retrieve date value

I'm currently writing code in SQL to add the column in red to the following table:
The logic is the following:
For every row:
if flag for this row =1 then use date of this row
if flag for this row =0 then find the latest row (based on date) on which flag was = 1 for the same party and return the date of that row. If no such row exists, return null
I've found a way to do this by joining the table to itself but I would like to avoid doing that as the size of the table is pretty massive.
What I have
select b.*, a.date,
from table a left join table b on a.party=b.party
where a.flag =1
Someone told me I could use the lag function, the partition over function and a case when to return the value I'm after but I haven't been able to figure it out.
Can someone help? Thank you so much!
try this
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0
select t.*,
max(case when flag = 1 then date end) over (partition by PARTY order by date) as [Last Flag On Date]
from #tab1 t
try this :->
select b.*, a.date, from table a left join table b on a.party=b.party where a.flag = CASE WHEN a.flag = 1 THEN a.date WHEN a.flag = 0 THEN ( SELECT date FROM ( SELECT TOP 1 row_number() OVER ( ORDER BY a.date DESC ) rs , a.date FROM a WHERE a.flag = 1 GROUP BY a.date) s ) END
use CROSS APPLY() to obtain the latest row with flag 1
SELECT *
FROM yourtable t
CROSS APPLY
(
SELECT TOP 1 x.Date as [Last flag on date]
FROM yourtable x
WHERE x.Party = t.Party
AND x.Flag = 1
ORDER BY x.Date desc
) d
Yes it can be done by joining table, if written properly.
#Sahi query is also good and simple.
Since you were asking for Dynamic LAG()
This query may or may not be very performant,but it certainly worth learning.
Test this with various sample data and tell me for which scenario it do not work.
So that I correct my script accordingly.
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0;
WITH cte
AS (SELECT *,
Row_number()
OVER (
partition BY party
ORDER BY flag DESC, [date] DESC ) rn
FROM #tab1)
SELECT *,
CASE
WHEN flag = 1 THEN [date]
ELSE Lag([date], (SELECT TOP 1 a.rn - a1.rn
FROM cte a1
WHERE a1.party = a.party))
OVER (
ORDER BY party )
END
FROM cte a

How do I get records before and after given one?

I have the following table structure:
Id, Message
1, John Doe
2, Jane Smith
3, Error
4, Jane Smith
Is there a way to get the error record and the surrounding records? i.e. find all Errors and the record before and after them.
;WITH numberedlogtable AS
(
SELECT Id,Message,
ROW_NUMBER() OVER (ORDER BY ID) AS RN
FROM logtable
)
SELECT Id,Message
FROM numberedlogtable
WHERE RN IN (SELECT RN+i
FROM numberedlogtable
CROSS JOIN (SELECT -1 AS i UNION ALL SELECT 0 UNION ALL SELECT 1) n
WHERE Message='Error')
WITH err AS
(
SELECT TOP 1 *
FROM log
WHERE message = 'Error'
ORDER BY
id
),
p AS
(
SELECT TOP 1 l.*
FROM log
WHERE id <
(
SELECT id
FROM err
)
ORDER BY
id DESC
)
SELECT TOP 3 *
FROM log
WHERE id >
(
SELECT id
FROM p
)
ORDER BY
id
Adapt this routine to pick out your target.
DECLARE #TargetId int
SET #TargetId = 3
select *
from LogTable
where Id in (-- "before"
select max(Id)
from LogTable
where Id < #TargetId
-- target
union all select #TargetId
-- "after"
union all select min(Id)
from LogTable
where Id > #TargetId)
select id,messag from
(Select (Row_Number() over (order by ID)) as RNO, * from #Temp) as A,
(select SubRNO-1 as A,
SubRNO as B,
SubRNO+1 as C
from (Select (Row_Number() over (order by ID)) as SubRNO, * from #Temp) as C
where messag = 'Error') as B
where A.RNO = B.A or A.RNO = B.B or A.RNO = B.C
;WITH Logs AS
(
SELECT ROW_NUMBER() OVER (ORDER BY id), id, message as rownum FROM LogTable lt
)
SELECT curr.id, prev.id, next.id
FROM Logs curr
LEFT OUTER JOIN Logs prev ON curr.rownum+1=prev.rownum
RIGHT OUTER JOIN Logs next ON curr.rownum-1=next.rownum
WHERE curr.message = 'Error'
select id, message from tbl where id in (
select id from tbl where message = "error"
union
select id-1 from tbl where message = "error"
union
select id+1 from tbl where message = "error"
)
Get fixed number of rows before & after target
Using UNION for a simple, high performance query (I found selected answer WITH query above to be extremely slow)
Here is a high performance alternative to the WITH top selected answer, when you know an ID or specific identifier for a given record, and you want to select a fixed number of records BEFORE and AFTER that record. Requires a number field for ID, or something like date that can be sorted ascending / descending.
Example: You want to select the 10 records before and after a specific error was recorded, you know the error ID, and can sort by date or ID.
The following query gets (inclusive) the 1 result above, the identified record itself, and the 1 record below. After the UNION, the results are sorted again in descending order.
SELECT q.*
FROM(
SELECT TOP 2
id, content
FROM
the_table
WHERE
id >= [ID]
ORDER BY id ASC
UNION
SELECT TOP 1
id, content
FROM
the_table
WHERE
id < [ID]
ORDER BY id DESC
) q
ORDER BY q.id DESC

Add results from several COUNT queries

I am trying to fetch the sum of several counts in one query:
SELECT(
SELECT COUNT( * )
FROM comments +
SELECT COUNT( * )
FROM tags +
SELECT COUNT( * )
FROM search
)
I am missing something here. I get syntax error.
SELECT ( SELECT COUNT(*) FROM comments )
+ ( SELECT COUNT(*) FROM tags )
+ ( SELECT COUNT(*) FROM search )
One more (not sure if supported with MySQL, though - works in SQL Server):
SELECT SUM(Counts) FROM
(SELECT COUNT(*) AS Counts FROM COMMENTS UNION ALL
SELECT COUNT(*) FROM Tags UNION ALL
SELECT COUNT(*) FROM Search) s
SELECT (
SELECT COUNT(*)
FROM comments
) +
(
SELECT COUNT(*)
FROM tags
) +
(
SELECT COUNT(*)
FROM search
)
SELECT SUM(ThisCount)
FROM (
SELECT COUNT(*) AS ThisCount
FROM comments
UNION ALL
SELECT COUNT(*) AS ThisCount
FROM tags
UNION ALL
SELECT COUNT(*) AS ThisCount
FROM search
)