SQL DELETE based on JOIN and aggregate condition - sql-server

I have two tables containing a category and a date.
Table 1:
cat date
A 20160102
A 20160103
A 20160104
B 20170202
B 20170203
B 20170204
Table 2:
cat date
A 20160103
A 20160104
A 20160105
B 20170203
B 20170206
B 20170207
I now want to delete all rows from Table 1 where the dates are equal or later than the earliest date of Table 2 per category.
The earliest date of category A is 20160103. The earliest date of category B is 20170203. Hence, the entries ('A','20160103'), ('A','20160104'), and ('B','20170204') should be deleted from Table 1.
For testing, I try to create a SELECT statement that selects the values which I want to delete. Currently I came up with this:
SELECT
t1.id
,t1.holiday
,MIN(t2.holiday)
FROM
table1 t1
INNER JOIN table2 t2
ON t2.id = t1.id
GROUP BY
t1.id
,t1.holiday
The next logical step (for me) would be to add the following WHERE clause
SELECT
t1.id
,t1.holiday
,MIN(t2.holiday)
FROM
table1 t1
INNER JOIN table2 t2
ON t2.id = t1.id
WHERE
t1.holiday >= MIN(t2.holiday)
GROUP BY
t1.id
,t1.holiday
However, this yields the following error:
An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
How can I solve this problem?

This answers the first question (about deleting from table 1)
DELETE t1
FROM Table1 AS t1
INNER JOIN (
SELECT
cat,
min_date=MIN([date])
FROM
Table2
GROUP BY
cat
) AS t2 ON
t2.cat=t1.cat
WHERE
t1.[date]>=t2.min_date

Related

Merging two columns with values from another table

I have similar table
How can i merge these two tables ? There are other columns, but these are the same.
How can i fill Table1 with values of Table2 or merge these tables ?
In Table2 is only 1 customer.
So the result table will have all customers with their values (Table1 will have Customer4 with Sales 50).
Thank you.
To update the table do
update t1
set t1.sales = t2.sales
from table1 t1
join table2 t2 on t1.customername = t2.customername
and as a select use
select t1.customername,
coalesce(t1.sales, t2.sales) as sales,
t1.date,
t1.variable1
from table1 t1
left join table2 t2 on t1.customername = t2.customername

SQL Server stored procedure select, exists, multiple tables

Any method to do this?
Table1
1
2
3
4
5
Table2
3 (with the condition)
4 (without the condition)
I want to:
Select all records from Table1 if it exists in Table 2, where...(condition)
Select all records from Table1 if it not exists in Table2
Combine both select results. Sort all results with their created date.
For example, the result should be:
Result
1
2
3
5
Hopefully this can help.
SELECT t1.* from table1 t1
JOIN table2 t2
ON t1.ID = t2.ID
UNION ALL
SELECT t1.* from table1 t1 where ID in
(
SELECT t2.ID from table1 t1 except Select t2.ID from table2 t2
)
ORDER BY t1.CreatedDate
You can achieve this by doing:
SELECT t1.id
FROM Table1 t1
LEFT JOIN Table2 t2 on t1.id = t2.id
WHERE condition OR t2.id IS NULL
ORDER BY t1.CreatedDate;
See fiddle (I assumed condition to be t2.id!=4, but it can be anything else depending on other data in your tables).
There could be multiple solution.
One way
we can get the result set using two different queries and at last combine both of the result-set using UNION
Another way,
First statement is saying that get all the result set from TABLE1 if it exists in TABLE2 as well with some criteria (condition in where clause)
means using INNER JOIN we can achieve this
Second statement is saying get all the result set from TABLE1 which are not present in TABLE2
means along with INNER JOIN ed query also include the TABLE1's data if not present in TABLE2
here we can take the help of LEFT OUTER JOIN (taking TABLE1 on the left side)
Assumption: (condition: t1.Id != 4)
Let's try to understand the query using both of the above mentioned ways
---- -- --Step1 Create table and insert records
---- create table1 with Id int identity columsn
--CREATE TABLE Table1 (Id INT IDENTITY(1,1), CreatedDate smalldatetime default(getdate()));
--go
---- insert 1st 5 integers into Table1
--INSERT INTO Table1 DEFAULT VALUES
--go 5
---- create Table2 with Id int column
--CREATE TABLE Table2 (Id INT , CreatedDate smalldatetime default(getdate()));
--go
---- insert records 3,5 into Table2
--INSERT INTO Table2(Id) VALUES (3), (4);
-- -- -- Solution: one way
; WITH cteMyFirstResult AS
(
-- 2.1. Select all records from Table1 if it exists in Table 2, where...(condition)
SELECT
Id, CreatedDate
FROM Table1 AS t1
WHERE t1.Id IN (SELECT Id FROM Table2 AS t2)
AND t1.Id != 4 -- assumption it can be any condition
),cteMySecondResult AS (
-- 2.2. Select all records from Table1 if it not exists in Table2
SELECT
Id, CreatedDate
FROM Table1 AS t1 WHERE t1.Id NOT IN (SELECT Id FROM Table2 AS t2)
)
-- 2.3. Combine both select results. Sort all results with their created date.
SELECT
Id, CreatedDate
FROM cteMyFirstResult
UNION
SELECT
Id, CreatedDate
FROM cteMySecondResult
ORDER BY CreatedDate;
-- -- Solution: Another way (with bug)
SELECT t1.Id, t1.CreatedDate
FROM Table1 AS t1
LEFT JOIN Table2 AS t2 on t1.id = t2.id
WHERE t1.Id != 4
Order by T1.CreatedDate;
-- in this query we are using the criteria after doing the join operation.
-- thus after filtering out the result set based on JOIN Condition this condition will get applied
-- and if there is any null record in the Table1 for column Id (used in join) will not come in the final result-set
-- to avoid this we can include NULL check along with our criteria
-- -- Solution: Another way
SELECT t1.Id, t1.CreatedDate
FROM Table1 AS t1
LEFT JOIN Table2 AS t2 on t1.id = t2.id
WHERE ( t1.Id != 4 ) OR t1.Id IS NULL -- include all your criteria within small-barcket)
Order by T1.CreatedDate;
Thanks for all responses.
I come out with the answer I want:
SELECT *
FROM Table1 t1
WHERE NOT EXISTS(SELECT 1 FROM Table2 t2
WHERE t1.ID = t2.ID
AND t2.CIF_KEY = #CifKey
AND t2.STATUS <> ''3'')
AND (condition in where clause)

Select matching records from Table 1 if Table 2 has records, otherwise select all from Table 1

Situation:
I have two tables
Table 1 always has records
Table 2 is the result of a select statement and may or may not have records
Desired Results:
If Table 2 has ANY records, I want only matching records from Table 1. Otherwise, I want all records from Table 1.
I realize I can do this:
DECLARE #count int
SELECT #count=COUNT(*) FROM Table2
IF #count>0
SELECT t1.* FROM Table1 t1 INNER JOIN Table2 t2 ON t1.id=t2.id
ELSE
SELECT * FROM Table1
However, I am trying to avoid IF statements if possible.
Is that even possible?
select t1.*
from Table1 t1
left join
Table2 t2
on t1.id = t2.id
where t2.id is not null -- Match found
or not exists -- Or Table2 is empty
(
select *
from Table2
)

To apply less than condition in delete query on the value obtained from select clause

I want to compare two table T1 and T2 and delete records from T1 which has form_no less than the form_no selected form T2.
I have written following query, but it is not working.
DELETE FROM T1
WHERE --Some Condition--
AND
FORM_NO < (ISNULL((SELECT DISTINCT(FORM_NO) FROM T2 WHERE --Some Condition--), 0))
Try this one... wish you could provide us the full query though..
DELETE FROM T1
WHERE --Some Condition--
AND FORM_NO IN (SELECT DISTINCT(t.FORM_NO) FROM T1 AS t
LEFT JOIN T2 AS s
ON -- COMMON COLUMN
WHERE t.FORM_NO < s.FORM_NO)
IF you have an common field and want to delete joining on this field:
delete from t11
from t1 t11
join t2 on (t11.commonID=t2.commonID)
where (t11.FORM_NO<t2.FORM_NO)
If you want exactly what you ask so:
delete from t1 where FORM_NO<(select min(FORM_NO) from t2)

Optimize CASE Test in SQL Server

I'm wondering if there's any way to optimize the following SELECT query. (Note: I typed this when writing my question for nonexistent tables and I might not have the correct syntax.)
The goal is, if Table2 contains any related rows I want to set the value of the third column to the number of related rows in Table2. Otherwise, if Table3 contains any related rows I want to set the column to the number of related rows in Table3. Otherwise, I want to set the column value to 0.
SELECT Id, Title,
CASE
WHEN EXISTS (SELECT * FROM Table2 t2 WHERE t2.RelatedId = Table1.Id) THEN
(SELECT COUNT(1) FROM Table2 t2 WHERE t2.RelatedId = Table1.Id)
WHEN EXISTS (SELECT * FROM Table3 t3 WHERE t3.RelatedId = Table1.Id) THEN
(SELECT COUNT(1) FROM Table3 t3 WHERE t3.RelatedId = Table1.Id)
ELSE 0
END AS RelatedCount
FROM Table1
I don't like the fact that I'm basically performing the same query twice (in two cases). Is there any way to do what I want while only performing the query once?
Note that this is part of a much larger query with multiple JOINs and UNIONs so it's not easy to take a completely different approach.
This query should perform much better. You are not just performing the same query twice; since they are correlated subqueries, they will run once per row.
SELECT Id, Title,
coalesce(t2.Count, t3.Count, 0) AS RelatedCount
FROM Table1 t
left outer join (
SELECT RelatedId, count(*) as Count
FROM Table2
group by RelatedId
) t2 on t1.Id = t2.RelatedId
left outer join (
SELECT RelatedId, count(*) as Count
FROM Table3
group by RelatedId
) t3 on t1.Id = t3.RelatedId

Resources