Delete Data from One Table using multiple tables in SQL Server - sql-server

I am trying to delete some data from one table using multiple table. The problem i am having with this query is that it is deleting data that is not suppose to delete. I want to delete only the Data where ID's in both tables are DIFFERENT. In other words, i want to keep when the ID's in both tables are the same. Here is my query:
delete Tabel1
from Table1 r join
Table2 w on r.ID <> w.ID
and w.Date_Assigned is not null

You probably want to do:
delete Tabel1 where Id not in (select Id from Table2)
Your statement will probably delete all records from Tabel1, because for every record it will find at least one in Tabel2 with a different ID.
To test this, just run
select r.ID
from Table1 r join
Table2 w on r.ID <> w.ID
and w.Date_Assigned is not null
and you'll understand what the problem is.

Related

TSQL - Return all record ids and the missing id's we need to populate

I have a job I need to automate to make sure a cache for some entities in my database is populated. I have the query below using CTE and CROSS JOIN but it doesn't run very quickly so I'm sure it can be improved.
The issue:
I have a database of employees
Each employee has a report of data compiled each month.
Each report has a set of 'components' and each of those components 'data' is pulled from an external source and cached in my database
The goal:
I want to set up a job to take a group of component Ids for 'this months report' and pre-cache the data if it doesn't exist.
I need to get a list of employees and the components they are missing in the cache for this months report. I will then set up a CRON job to process the queue.
The Question
My query below is slow - Is there a more efficient way to return a list of employees and the component ids that are missing in the cache?
The current SQL:
declare #reportDate datetime2 = '2019-10-01'; //the report publish date
declare #componentIds table (id int); // store the ids of each cachable component
insert #componentIds(id) values(1),(2),(3),(4),(5);
;WITH cteCounts
AS (SELECT r.Id as reportId, cs.componentId,
COUNT(1) AS ComponentCount
FROM EmployeeReports r
LEFT OUTER JOIN CacheStore cs on r.Id = cs.reportId and cs.componentId in (SELECT id FROM #componentIds)
GROUP BY r.Id, cs.componentId)
SELECT e.Id, e.name, _c.id as componentId, r.Id as reportId
FROM Employees e
INNER JOIN EmployeeReports r on e.Id = r.employeeId and r.reportDate = #reportDate
CROSS JOIN #componentIds _c
LEFT OUTER JOIN cteCounts AS cn
ON _c.Id = cn.componentId AND r.Id = cn.reportId
WHERE cn.ComponentCount is null
2 things I can suggest doing:
Use NOT EXISTS instead of a LEFT JOIN + IS NULL. The execution plan is prone to be different when you tell the engine that you want records that don't have any occurrence in a particular set Vs. joining and making sure that the joined column is null.
SELECT e.Id, e.name, _c.id as componentId, r.Id as reportId
FROM Employees e
INNER JOIN EmployeeReports r on e.Id = r.employeeId and r.reportDate = #reportDate
CROSS JOIN #componentIds _c
WHERE
NOT EXISTS (SELECT 'no record' FROM cteCounts AS cn
WHERE _c.Id = cn.componentId AND r.Id = cn.reportId)
Use temporary tables instead of CTE and/or variable tables. If you have to handle many rows, variable tables don't actually have statistics on and some complex CTE's might actually make lousy execution plans. Try using temporary tables instead of these 2 and see if the performance boosts. Also try creating relevant indexes on them if your row count is high.

How to restore SQL data from one table to another

I have a backup table with 15,000 rows. The data was directly copied from a main table. I need to perform an UPDATE statement on the main table, using the data from the backup table. Both tables are identical in structure and use a unique primary key called ID.
How do I loop through the backup table, find the matching record for each row in the main table, and then replace each record in main table with the matching record in the backup table?
Thanks
EDIT:
Proposed Solution based on Sean Lange's comment:
UPDATE a
SET a.col1 = b.col1
, a.col2 = b.col2
FROM table1 a
INNER JOIN table2 b
ON a.id = b.id
You can use a JOIN update to accomplish this. Assuming they have matching primary key ID's, it should be quick and painless.
UPDATE table1
SET a.col1 = b.col2
, a.col2 = b.col2
FROM table1 a
INNER JOIN table2 b
ON a.id = b.id

Shortcut for adding table to column name SQL-server 2014

Stupidly simple question, but I just don't know what to google!
If I create a query like this:
Select id, data
from table1
Now I want to join with table2. I can immediately see that the id column is no longer unique and I have to change it to
table1.id
Is there any smart way (like a keyboard-shortcut) to do this, instead of manually adding table1 to every column? Either before I add the Join to secure that all columns will be unique, or after with suggestions based on the different possible tables.
No, there is no helper.
But do not you can alias the table name:
select x.Col1, y.Col2
from ALongTableName x
inner join AReallyReallyLongTableName y on x.Id = y.OtherId
which can also make queries clearer, and is very much necessary when doing self joins.
First of all, you should start using aliases:
SQL aliases are used to give a database table, or a column in a table,
a temporary name.
Basically aliases are created to make column names more readable.
This will narrow down your problem and make your code maintenance easier. If that's not enough, I guess you could start using auto-completion tools, such as these:
SQL Complete
SQL Prompt
ApexSQL Complete
These have your desired functionality, however, they do not always work as expected (at least for me).
Oh! You can use alias table name. Like this:
SELECT A.ID, A.data
FROM TableA A
INNER JOIN TableB B
ON A.ID = B.ID
You just only use A. or B. if two table have same this column selected. If they different, you don't need: Like this:
SELECT A.ID, data -- if Table B not have column data
FROM TableA A
INNER JOIN TableB B
ON A.ID = B.ID
Or:
Select A.*, B.ID
FROM TableA A
INNER JOIN TableB B
ON A.ID = B.ID

How to get the latest inserted identity from a table?

I would like to retrieve the latest inserted or even updated identity from a table. But whenever I write the following code there is no results at all.
select *
from PersonHowEducation prh
inner join HowzeEducation he on prh.HowzeEducationId = he.HowzeEducationId
where he.HowzeEducationId = ##IDENTITY
What shall I really do ?
If this were part of a batch script, and you have only just inserted it in the same session, then you would use SCOPE_IDENTITY() to retrieve the last inserted HowzeEducationId value.
select * from PersonHowEducation prh inner join HowzeEducation he on
prh.HowzeEducationId=he.HowzeEducationId
where he.HowzeEducationId=SCOPE_IDENTITY()
However, if this is from a completely different session, one that DID NOT JUST perform the insert, then you can get the last record inserted using
select * from PersonHowEducation prh inner join HowzeEducation he on
prh.HowzeEducationId=he.HowzeEducationId
where he.HowzeEducationId=(select top(1) HowzeEducationId from HowzeEducation
order by HowzeEducationId desc)
Note: There could be rare cases where an identity insert does not create the largest id in the table, for example if someone decided a table should have 1 record of id= 1,000,000,001 and manually reseeded the identity back to 10,001.
Another alternative, which may fizz if it is possible for the record to be deleted after insertion.
select * from PersonHowEducation prh inner join HowzeEducation he on
prh.HowzeEducationId=he.HowzeEducationId
where he.HowzeEducationId=(SELECT IDENT_CURRENT('HowzeEducation'))

Updating a table with missing records from another table

I am running a query that returns records from the LEFT of the EXCEPT that are not on the right query;
USE AdventureWorks;
GO
SELECT ProductID
FROM Production.Product
EXCEPT
SELECT ProductID
FROM Production.WorkOrder;
Lets say there are 6 records returned (there are 6 records in Production.Product table, that are not in Production.WorkOrder)
How would I write the query to update the 6 records into Production.WorkOrder table?
insert into workorder (productid)
select productid from product where productid not in (select productid from workorder)
This will insert into workorder all the productid's in the product table that aren't already in workorder.
I'd use a left join, like this:
USE AdventureWorks;
GO
SELECT p.ProductID
FROM Production.Product p
LEFT
JOIN Production.WorkOrder wo
ON p.ProductID = wo.ProductID
WHERE wo.ProductID IS NULL;
This will return all the ProductID values from Product that do not appear in WorkOrder. The problem with the other answer (WHERE NOT IN) is that the sub-query will execute once/row, and if the tables are large, this will be really slow. A LEFT JOIN will only execute once, and then SQL will match the rows up - on a small table, there won't be much difference in practice, but on a larger table or in a production database, the difference will be immense.
Just turn your query into an INSERT?
INSERT INTO Production.WorkOrder(ProductID, ...)
SELECT ProductID, ...
FROM Production.Product
EXCEPT
SELECT ProductID
FROM Production.WorkOrder;

Resources