Select with not exist in the same table with multiple fields - sql

I need to select registers from table that not exist in the same table. I mean if i have this table:
ID VALUE1 VALUE2 VALUE3
1 1 1 1
2 2 2 1
3 3 4 1
4 1 5 1
5 2 2 2
6 3 4 2
7 1 8 2
8 2 2 2
The result of the query should be
ID VALUE1 VALUE2 VALUE3
1 1 1 1
4 1 5 1
Because the rest of the values are the same for the value1 and value2 but diferent value3. I mean the row 2 of the table is the same that the row 5.
I try to do something like but not works:
select t1.value1, t1.value2 from table1 t1 where value3=1
and not exist
(select t2.value1, t2.value2 from table2 t2
where t1.value1=t2.value1 and t1.value2=t2.value2 and value3=2)
Thank you in advise and sorry for my english

You can use the NOT EXISTS as follows:
SELECT *
FROM YOUR_TABLE T1
WHERE T1.VALUE3 = 1
AND NOT EXISTS
(SELECT 1
FROM YOUR_TABLE T2
WHERE T1.VALUE1 = T2.VALUE1
AND T1.VALUE2 = T2.VALUE2)

I think not exists does what you want:
select t1.*
from table1 t1
where t1.value3 = 1 and
not exist (select 1
from table2 t2
where t2.value1 = t1.value1 and
t2.value2 = t1.value2 and
t2.value3 = 2
);
That said, you can also use window functions:
select t1.*
from (select t1.*,
max(value3) over (partition by value1, value2) as max_value3
from table1 t1
where value3 in (1, 2)
) t1
where max_value3 = 1;

I think that you are on the right track with exists.
I would phrase your query like:
select t1.*
from table1 t1
where
t1.value3 = 1
and not exist (
select 1 from table1 t2
where t1.value1 = t2.value1 and t1.value2 = t2.value2 and t2.value3 = 2
)
Key points:
the exists subquery should be from table1 (your query uses table2 but it seems like this table does not actually exists)
you don't actually need to return columns from the exists subquery, since all it does is check if some row is produced - hence the select 1

Related

SQL only join when key matches one criteria

I have two tables that look like the following:
Table 1 (IDs):
ID
1
2
3
4
5
Table 2 (Categories):
ID CAT
1 A
1 B
2 A
3 A
4 B
5 A
5 B
5 C
What I would like to do is join table 2 to table 1 and only keep instances where there is 1) Only one match 2) That match is CAT = A
So my final table would look like:
ID CAT
2 A
3 A
One method is aggregation and having:
select id, max(cat)
from t
group by id
having count(*) = 1 and
max(cat) = 'A';
You can use a subquery with not exists:
select t1.id, t2.cat
from table1 t1
join table2 t2 on t1.id = t2.id
where t2.cat = 'A' and not exists (select 1 from table2 t3 where t3.id = t1.id and t3.cat != 'A');
Output:
id
cat
2
A
3
A

SQL: How do I delete rows that are also in another table?

Say I have two tables. E.g,
Table 1:
Store Product
1 2
1 1
2 3
2 4
And Table 2
Store Product
1 2
2 3
How do I delete all the rows in Table 1 that are also in Table 2?
So, new Table 1 would be:
Store Product
1 1
2 4
You seem want :
select t1.*
from table1 t1
where not exists (select 1
from table2 t2
where t2.store = t.store and
t2.product = t1.product
);
Similarly delete version would be :
delete
from table1 t1
where exists (select 1
from table2 t2
where t2.store = t.store and
t2.product = t1.product
);
You can use something like this:
DELETE
t1
FROM
table1 t1
WHERE
(t1.store, t1.product) IN ( SELECT
t2.store,
t2.product
from
table2 t2);

SQL query with one to many relation

I have following table
Table1
id name col1 col2 col3 col4
-----------------------------------
1 test 1.1 1.2 1.3 1.4
2 test2 2.1 2.2 2.3 2.4
Table2
id fk_table1 amt type(fk_table3)
-----------------------------------
1 1 2 1
2 1 3 1
3 1 9 2
4 2 1 1
and I want to query such that I have get below result
id | name | total_type1_amt |total_type2_amt | col1 col2 col3 col4
-----------------------------------------------------------------------
1 test 5 (2+3) 9 1.1 1.2 1.3 1.4
2 test2 1 0 2.1 2.2 2.3 2.4
Basically in result I want group by table1.id with added columns for total_typeX_amt, there will be millions of rows in table1 and table2 so basically looking for optimized way to do it.
SELECT t1.id,
t1.name,
t2.total_type1_amt,
t2.total_type2_amt
FROM table1 t1
INNER JOIN
(
SELECT fk_table1,
SUM(CASE WHEN type = 1 THEN amt END) AS total_type1_amt,
SUM(CASE WHEN type = 2 THEN amt END) AS total_type2_amt
GROUP BY fk_table1
) t2
ON t1.id = t2.fk_table1
If you need this to run fast, you can try creating a view using the subquery (which I called t2 above), with an index on the fk_table1 column. Assuming that table1 also has an index on id, then the join should run reasonably fast.
It's not 100% your desired result, but you could try something like
select fk_table1, type, sum(amt)
from table1
inner join table2 on table1.id = table2.fk_table1
group by fk_table1, type
which should lead to something like
fk_table1 | type | sum
1 1 5
1 2 9
2 1 1
try dis to get total for total_type1_amt
select table1.id, table2.name ,(select count(table2.amt) as total_type1_amt where table1.id = table2.fk_table1 from table.1) from table1
inner join table2 on table1.id = table2.fk_table1
group by table.id
SELECT
T1.id,
T1.name,
SUM(CASE T2.type WHEN 1 THEN T2.amt ELSE 0 END) AS total_type1_amt,
SUM(CASE T2.type WHEN 2 THEN T2.amt ELSE 0 END) AS total_type2_amt
FROM #tbl1 T1
LEFT JOIN #tbl2 T2 ON T1.id=T2.fk_table1
GROUP BY T1.id,T1.name
Output:
You can try like this
;WITH cte
AS (SELECT
fk_table1, SUM([1]) total_type1_amt, COALESCE(SUM([2]), 0) total_type2_amt
FROM #table1 PIVOT (MAX(amt) FOR type IN ([1], [2])) p
GROUP BY fk_table1)
SELECT
t.id, t.name, c.total_type1_amt, c.total_type2_amt
FROM #table1 t
LEFT JOIN cte c
ON t.id = c.fk_table1
There at least 2 ways:
SELECT t1.id,
t1.name,
COALESCE(SUM(CASE WHEN [type] = 1 THEN amt END),0) AS total_type1_amt,
COALESCE(SUM(CASE WHEN [type] = 2 THEN amt END),0) AS total_type2_amt,
col1,
col2,
col3,
col4
FROM table1 t1
LEFT JOIN table2 t2
ON t1.id = t2.fk_table1
GROUP BY t1.id, t1.name, col1, col2, col3, col4
Another:
SELECT *
FROM (
SELECT t1.id,
t1.name,
t2.[type],
SUM(t2.amt) as sum
FROM table1 t1
LEFT JOIN table2 t2
ON t1.id = t2.fk_table1
GROUP BY t1.id, t1.name, t2.[type]
) as t
PIVOT (
MAX(sum) FOR type IN ([1],[2])
) as pvt

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)

Joining two tables in a select

I have two tables:
TABLE 1
ID VALUE
1 ABC
2 DEF
3 GHI
4 JKL
5 XYZ
TABLE 2
ID T1_ID VALUE
1 1 A
2 1 B
3 2 A
4 3 A
5 3 B
6 4 B
I want to select all rows from TABLE 1 which have a TABLE 2 row for Values A AND B.
This would be rows 1 and 3 (not 2 because it has only A, not 4 because it has only B).
Can I do this without a subquery?
(Note: I also need to query against values in table 1 so I can't just query table 2.)
Tadaaah! Without a subquery.
select distinct
t1.*
from
Table1 t1
inner join Table2 t2a on t2a.t1_ID = t1.ID and t2a.VALUE = 'A'
inner join Table2 t2b on t2b.t1_ID = t1.ID and t2b.VALUE = 'B'
SELECT t1.ID,
t1.VALUE
FROM Table1 t1
JOIN Table2 t2
ON t1.ID = t2.T1_ID
WHERE t2.VALUE IN ( 'A', 'B' )
GROUP BY t1.ID,
t1.VALUE
HAVING COUNT(DISTINCT t2.VALUE) = 2