Return matching rows only SQL Server - sql

I am sure this simple but i am really stuck. Here is a example of the resultset i want from two tables that have the same structure and in this case data or records
TableA
Ref cola colb id
------------------
1 a b 14
1 a b 24
TableB
Ref cola colb id
------------------
1 a b 1
1 a b 2
1 a b 3
Expected result:
Ref cola colb id Ref1 cola1 colb1 id1
----------------------------------------
1 a b 14 1 a b 1
1 a b 24 1 a b 2

Use:
SELECT *
FROM table1 t1
JOIN Table2 t2
ON t1.Ref =t2.Ref AND t1.cola = t2.cola
AND t1.colb = t2.colb AND t1.id = t2.id
or
SELECT *
FROM table1 t1
JOIN Table2 t2
USING ( Ref , cola , colb, id )

one more way would be
;with cte
as
(
select Ref, cola, colb, id,
hashbytes('sha1',concat(Ref, cola, colb)) as tb1hash
from table1
)
select
t1.Ref, --all required cols
from cte c
join
(
select Ref, cola, colb, id,
hashbytes('sha1',concat(Ref, cola, colb)) as tb2hash
from table2
) b
on
b.tb2hash=c.tb1hash

Guessing:
;WITH TableAWithRowNum
AS (
SELECT *, ROW_NUMBER(ORDER BY id) AS RowNum
FROM dbo.TableA
), TableBWithRowNum
AS (
SELECT *, ROW_NUMBER(ORDER BY id) AS RowNum
FROM dbo.TableB
)
SELECT a.*, b.*
FROM TableAWithRowNum a
INNER JOIN TableBWithRowNum b ON a.Ref = b.Ref
--AND other join predicates on ColA, ... etc.
AND a.RowNum = b.RowNum

Related

Order by in subquery and alias

I have a problem with a order by in oracle query.
select KEY, B, C, (select D from TABLE1 a where a.KEY = b.KEY and a.DATE<
b.DATE order BY a.DATE and rownum =1 )
FROMSTATUS from TABLE2 b
I known the "order by" is not working in subquery. I modify my query as:
select KEY, B, C, (select * from (select D from TABLE1 a where a.KEY =
b.KEY and a.DATE< b.DATE order by DATE) where rownum = 1)
FROMSTATUS from TABLE2 b
But in this way the B.KEY and B.DATE has not resolved by oracle
I need select only a 1 value from TABLE2 and the value is the first previous a.DATE
Example:
TABLE1
KEY DATE A B C
1 01/31/2000 1 2 3
2 02/25/2000 X Y Z
TABLE2
KEY DATE D
1 01/30/2000 1
1 01/27/2000 2
1 01/25/2000 2
2 02/20/2000 4
2 02/13/2000 1
I need this result:
TABLE1.KEY TABLE1.DATE TABLE1.A TABLE1.B TABLE1.C TABLE2.DATE TABLE2.D
1 01/31/2000 1 2 3 01/30/2000 1
2 02/25/2000 X Y Z 02/20/2000 4
Can you help me?
(i am sorry for my bad english)
row_number() after union will get your output.
select tFinal.DATE, tFinal.KEY
from (select row_number() over (partition by KEY order by t1.T, t1.DATE desc) as rn, t1.DATE, t1.KEY
from
(select DATE, KEY, 't1' as T from TABLE1
union all
select DATE, KEY, 't2' as T from TABLE2) t1) tFinal
Where rn = 2
You can use window functions for this:
WITH cte AS (
SELECT TABLE2.KEY, TABLE2.B, TABLE2.C, TABLE1.D
, ROW_NUMBER() OVER (PARTITION BY TABLE2.KEY, TABLE2.DATE ORDER BY TABLE1.DATE DESC) AS rn
FROM TABLE2
LEFT JOIN TABLE1 ON TABLE2.KEY = TABLE1.KEY AND TABLE2.DATE > TABLE1.DATE
)
SELECT *
FROM cte
WHERE rn = 1
Here's an answer that uses aggregation:
WITH t1 AS (SELECT 1 KEY, to_date('31/01/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 2 KEY, to_date('25/02/2000', 'dd/mm/yyyy') dt FROM dual),
t2 AS (SELECT 1 KEY, to_date('30/01/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 1 KEY, to_date('27/01/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 1 KEY, to_date('25/01/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 2 KEY, to_date('20/02/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT 2 KEY, to_date('13/02/2000', 'dd/mm/yyyy') dt FROM dual)
SELECT t1.KEY,
t1.dt t1_date,
MAX(t2.dt) t2_date
FROM t1
LEFT OUTER JOIN t2 ON t1.key = t2.key AND t2.dt < t1.dt
GROUP BY t1.key, t1.dt
ORDER BY t1.key;
KEY T1_DATE T2_DATE
---------- ----------- -----------
1 31/01/2000 30/01/2000
2 25/02/2000 20/02/2000
I'm assuming here that t1.key is a unique column. Whether this is more performant than any of the other answers for your data is up to you to test *{:-)
In Oracle you can use KEEP LAST for this:
select
key,
b,
c,
(
select max(d) keep (dense_rank last order by t2.date)
from table2 t2
where t2.key = t1.key and t2.date < t1.date
) as fromstatus
from table1 t1;
As of Oracle 12c you can also use FETCH FIRST ROW:
select
key,
b,
c,
(
select d
from table2 t2
where t2.key = t1.key and t2.date < t1.date
order by t2.date desc
fetch first row only
) as fromstatus
from table1 t1;
or, moving the subquery to the FROM clause:
select
t1.key,
t1.b,
t1.c,
first_t2.d as fromstatus
from table1 t1
outer apply
(
select d
from table2 t2
where t2.key = t1.key and t2.date < t1.date
order by t2.date desc
fetch first row only
) first_t2;
This last query has the advantage that you could easily select more values from the table2 row than just one.

Equally divide a field into 2

How can I equally divide the 'col' field of table 't2' with a,b,c,d as records into 2 equal fields : Col1 (a,b) & Col2 (c,d)?
Table:t2
Col
A
B
C
D
Output:
Col1 Col2
A C
B D
this is what i have tried:
SELECT a.col1, "" as col2
FROM (SELECT Top 50 Percent Col as Col1 From t2 order by Col ASc) as a
Union all
SELECT "", b.col1
FROM (SELECT top 50 Percent Col as Col1 From t2 order by Col Desc) as b
Output from above:
col1 col2
a
b
d
c
I'm only able to reach so far (in Ms access). Any help is much appreciated.
Create table 't2'
Create Table t2(Col Char)
Insert Values
INSERT INTO t2 ([Col]) VALUES ("a")
INSERT INTO t2 ([Col]) VALUES ("b")
INSERT INTO t2 ([Col]) VALUES ("c")
INSERT INTO t2 ([Col]) VALUES ("d")
Yes, you can use a crosstab if you have a sequential ID:
TRANSFORM
First(T.Col) AS Col
SELECT
([ID]+1)\2 AS DualID
FROM
(SELECT ID, [ID] Mod 2 AS ColID, [Col]
FROM YourTable) AS T
GROUP BY
([ID]+1)\2
PIVOT
T.ColID;
SELECT A1.COL1 & "-" & B1.COL1 AS PAIRS
FROM
(SELECT TOP 50 PERCENT A.Col AS COL1 FROM t2 AS A ORDER BY A.Col ASC) AS A1
INNER JOIN
(SELECT TOP 50 PERCENT B.Col AS COL1 FROM t2 AS B ORDER BY B.Col DESC) AS B1
ON A1.COL1 <> B1.COL1
WHERE (SELECT COUNT(*) FROM t2 AS C WHERE C.Col < A1.COL1) = (SELECT
COUNT(*) FROM t2 AS D WHERE D.Col > B1.COL1)

SQL Complex join not giving distinct result

I have two tables :-
Table1:-
ID1
1
1
1
1
4
5
Table2:-
Id2
2
2
1
1
1
8
I want to show all the ID2 from table2 which are present in ID1 of table1 by using joins
I used :-
select ID2 from Table2 t2 left join Table1 t1
on t2.Id2=t1.Id1
But this was giving repeated result as :-
Id2
1
1
1
1
1
1
1
It should show me 1 as 3 times only as it is present in Table2 3 times.
Please help.
You're matching the value 1 with 4 rows on Table1 and 3 rows on Table2 that's why you're seeing 12 rows. You need an additional JOIN condition. You can add a ROW_NUMBER and do an INNER JOIN to achieve your desired result.
WITH Cte1 AS(
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY Id1 ORDER BY (SELECT NULL))
FROM Table1
),
Cte2 AS(
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY Id2 ORDER BY (SELECT NULL))
FROM Table2
)
SELECT c2.Id2
FROM Cte2 c2
INNER JOIN Cte1 c1
ON c1.Id1 = c2.Id2
AND c1.rn = c2.rn
However, you can achieve the desired result without using a JOIN.
SELECT *
FROM Table2 t2
WHERE EXISTS(
SELECT 1 FROM Table1 t1 WHERE t1.Id1 = t2.Id2
)
It's the expected behavior of Join Operation. It will match every row from the two tables, so you will get 12 rows containing value 1 in result of join query.
You can use below query to get desired result.
select ID2 from Table2 t2 WHERE ID2 IN (SELECT ID1 FROM Table1 t1)
select id2 from table2 t2 where exists ( select 1 from table1 t1 where t1.id1 = t2.id2)
Your join logic works fine, the problem is each of your ID2 is matching against all ID1s. A simple solution would be to join with a table of distinct ID1s to avoid this duplication.
select
t2.ID2
from Table2 t2
left join (select distinct * from Table1) t1
on t1.Id1=t2.Id2
where t1.ID1 is not null
;
Here is a functional example
This will select your entire ID2 list with ID1 populated in a column. ID1 is null where there was no match. Select your ID2 column from this table but just don't pull null values (with where clause):

require to form a sql query

I was working on preparing a query where I was stuck.
Consider tables below:
table1
id key col1
-- --- -----
1 1 abc
2 2 d
3 3 s
4 4 xyz
table2
id col1 foreignkey
-- ---- ----------
1 12 1
2 13 1
3 14 1
4 12 2
5 13 2
Now what I need is to select only those records from table1 for which the corresponding entries in table2 does not have say col1 value as 12.
So the challenge is after applying join even though it will skip for value 1 corresponding to col1 equal to 12 it still has another multiple rows whose values are say 13, 14 for which also they have same foreignkey. Now what I want is if there is a single row having value 12 then it should not pick that id at all from table1.
How can I form a query with this?
The output which i need is say from above table structure i want to get those records from table1 for which col1 value from table2 does not have value as 14.
so my query should return me only row 2 from table1 and not row 1.
Another way of doing that. The first two queries are just for making the sample data.
;WITH t1(id ,[key] ,col1) AS
(
SELECT 1 , 1 , 'abc' UNION ALL
SELECT 2 , 2 , 'd' UNION ALL
SELECT 3 , 3 , 's' UNION ALL
SELECT 4 , 4 , 'xyz'
)
,t2(id ,col1, foreignkey) AS
(
SELECT 1 , 12 , 1 UNION ALL
SELECT 2 , 13 , 1 UNION ALL
SELECT 3 , 14 , 1 UNION ALL
SELECT 4 ,12 , 2 UNION ALL
SELECT 5 ,13 , 2
)
SELECT id, [key], col1
FROM t1
WHERE id NOT IN (SELECT t2.Id
FROM t2
INNER JOIN t1 ON t1.Id = t2.foreignkey
WHERE t2.col1 = 14)
This is a typical case for NOT EXISTS:
SELECT id, [key], col1
FROM table1 t1
WHERE NOT EXISTS (SELECT 1
FROM table2 t2
WHERE t2.foreignkey = t1.id AND t2.col1 = 14)
The above query will not select a row from table1 if there is a single correlated row in table2 having col1 = 14.
Output:
id key col1
-------------
2 2 d
3 3 s
4 4 xyz
If you want to return records that, in addition to the criterion set above, also have correlated records in table2, then you can use the following query:
SELECT t1.id, MAX(t1.[key]) AS [key], MAX(t1.col1) AS col1
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.foreignkey
GROUP BY t1.id
HAVING COUNT(CASE WHEN t2.col1 = 14 THEN 1 END) = 0
Output:
id key col1
-------------
2 2 d
You can also achieve the same result with the second query using a combination of EXISTS and NOT EXISTS:
SELECT id, [key], col1
FROM table1 t1
WHERE EXISTS (SELECT 1
FROM table2 t2
WHERE t2.foreignkey = t1.id)
AND
NOT EXISTS (SELECT 1
FROM table2 t3
WHERE t3.foreignkey = t1.id AND t3.col1 = 14)
select t1.id,t1.key,
(select ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col1 DESC) AS Row,* into
#Temp from table1)
from table1 t1
inner join table2 t2 on t1.id=t2.foreignkey
where t2.col1=(select col1 from #temp where row>1)

SQL to filter table with similar value

I have these data in table1
table1
ColA ColB ColC ColD
A B C D
A B G F
A B C G
G B C F
A B C H
I am trying to create a sql statment such that search for same value in ColB and then same value in ColD
table1
ColA ColB ColC ColD
A B G F
G B C F
I tried
select * from table1 where ColB = ColB and ColD = ColD.
Is there anyway I can filter out similar data appear in ColB and ColD using one sql statement?
"similar columns":
select colB, ColD
from table1
group by colB, ColD
having count(*) > 1
Data that have "simillar columns":
select *
from table1
join ( select colB, ColD
from table1
group by colB, ColD
having count(*) > 1
) a on table1.colB = a.colB and table1.colD = a.colD
Another approach would be:
select * from (
select
s.*,
count(*) over (partition by colB, ColD) as cnt
from table1 s
)
where cnt > 1