Writing the SQL query based on 2 tables - sql

I am really confused writing this SQL query, it might be easy but I still cannot come to the right solution.
Idea: Delete rows (foreign keys) from TableA based on TableB, if in TableB exist Primary Keys which match some other value within TableB.
For table B it should look like this:
SELECT Column1
FROM TableB
WHERE Column2 = 'Value';
And then
Delete rows in TableA which match to values inside of Column1 (TableB).

IN operator is good when you have hard coded values in IN operator like where SomeCoumn IN ('value1', 'Value2')
Or you are checking against a Primary key column like WHERE SomeColumn IN (select PK_Column from SomeTable)
Because in either of the above cases you will not have a NULL value inside your IN operator.
Null values inside IN operator brings back unexpected results.
A better option would be to use Exists operator... something like....
DELETE FROM TableA
WHERE EXISTS ( SELECT 1
FROM TableB
WHERE TableA.ColumnX = TableB.Column1
AND TableB.Column2 = 'Value'
);

Assuming that you need to match ColumnX in TableA:
DELETE FROM TableA
WHERE ColumnX IN (SELECT Column1
FROM TableB
WHERE Column2 = 'Value');

Related

SQL 0 results for 'Not In' and 'In' when row does exist

I have a table (A) with a list of order numbers. It contains a single row.
Once this order has been processed it should be deleted. However, it is failing to be deleted.
I began investigating, a really simple query is performed for the deletion.
delete from table(A) where orderno not in (select distinct orderno from tableB)
The order number absolutely does not exist in tableB.
I changed the query in SSMS to :
select * from table(A) where orderno not in (select distinct orderno from tableB)
This returned 0 rows. Bare in mind the orderno does exist in tableA.
I then changed the query from "not in" to "In". It still returned 0 rows. How can this be possible that a value is not in a list of values but also not show for the opposite?
Things I have tried:
Two additional developers to look over it.
ltrim(rtrim()) on both the select values.
Various char casts and casting the number as an int.
Has anyone experienced this?
Don't use NOT IN with a subquery. Use NOT EXISTS instead:
delete from tableA
where not exists (select 1 from tableB where tableA.orderno = tableB.orderno);
What is the difference? If any orderno in TableB is NULL, then NOT IN returns NULL. This is correct behavior based on how NULL is defined in SQL, but it is counterintuitive. NOT EXISTS does what you want.
You can use not exists
select *
from table(A) a
where not exists (selet 1 from tableB where orderno = a.orderno);
I have experienced the same.
try joining the two tables tableA and TableB
select * from TableA a
inner join TableB b on a.orderno =b.orderno
This should allow you to get the records and then you can delete the same.

t-sql defect when selecting an non-existent column from a temp table [duplicate]

I have a piece of SQL which (you would think) wouldn't compile, but which instead deletes all rows from the target table.
Consider this setup:
create table TableA (ColumnA varchar(200));
create table TableB (ColumnB varchar(200));
insert TableA values ('A'),('B'),('C');
insert TableB values ('A');
Then the following sql:
--Returns all rows from TableA
select * from TableA;
--Does not error (ColumnA does not exist on TableB)
delete TableA where ColumnA in (select ColumnA from TableB)
--No Rows are returned
select * from TableA;
The delete statement above causes all rows to be removed from TableA, rather than erroring that ColumnA doesn't exist in TableB
There's a SQL Fiddle demontrating this here: http://www.sqlfiddle.com/#!3/9d883/6
It seems that the ColumnA from TableA is being picked up, but expected it to be "out of scope".
Why is this?
That works as expected, due to the correlation between ColumnA in the inner query to the outer.
This commonly used correlated query pattern is valid
DELETE TableA WHERE NOT EXISTS (select * from TableB where TableB.ID=TableA.ID)
It removes TableA entries that don't have a dependent record in TableB.
It shows that you can reference TableA columns in a correlated query. In your query
delete TableA where ColumnA in (select ColumnA from TableB)
The inner query is producing
one row for each record in TableB
one column for each row, whose value is ColumnA from outer query
So the DELETE goes through
While I understand the confusion, it is behaving as it should. ColumnA is still "in scope". In fact you could join on it in your subquery if you wanted. The brackets don't limit the scope, but from a readability standpoint I can see the confusion that it creates.
This is another example of why it's a good idea to always prefix your column names with the table name (or alias).

How to loop through rows in two tables and create a new set based on the merged results in SQL

Here is my obstacle.
I have two tables. Table A contains more rows than Table B. I have to merge the results and if Table A does not contain a row from Table B then I insert it into the new set. If however, a row from Table A contains a row with the same primary key as Table B, the new set will take the row from Table B.
Would this best be done in a cursor or is there an easier way to do this? I ask because there are 20 million rows and while I am new to sql, i've heard cursors are expensive.
Your phrasing is a little vague. It seems that you want everything from TableB and then rows from TableA that have no matching primary key in B. The following query solves this problem:
select *
from tableB union all
select *
from tableA
where tableA.pk not in (select pk from tableB)
Yep, cursors are expensive.
There's a MERGE command in later versions of SQL that will do this in one shot, but it's sooo cumbersome. Better to do it in two pieces - first:
UPDATE A SET
field1 = B.field1
,field2 = B.field2
, etc
FROM A JOIN B on B.id = A.id
Then:
INSERT A SELECT * FROM B --enumerate fields if different
WHERE B.id not in (select id FROM A)
An OUTER JOIN should do what you need and be more efficient than a cursor.
Try this query
--first get the rows that match between TableA and TableB
INSERT INTO [new set]
SELECT TableB.* --or columns of your choice
FROM TableA LEFT JOIN TableB ON [matching key criteria]
WHERE TableB.[joining column/PK] IS NOT NULL
--then get the rows from TableA that don't have a match
INSERT INTO [new set]
SELECT TableA.* --you didn't say what was inserted if there was no matching row
FROM TableA LEFT JOIN TableB ON [matching key criteria]
WHERE TableB.[joining column/PK] IS NULL

SQL Select Into Field

I want to accomplish something of the following:
Select DISTINCT(tableA.column) INTO tableB.column FROM tableA
The goal would be to select a distinct data set and then insert that data into a specific column of a new table.
SELECT column INTO tableB FROM tableA
SELECT INTO will create a table as it inserts new records into it. If that is not what you want (if tableB already exists), then you will need to do something like this:
INSERT INTO tableB (
column
)
SELECT DISTINCT
column
FROM tableA
Remember that if tableb has more columns that just the one, you will need to list the columns you will be inserted into (like I have done in my example).
You're pretty much there.
SELECT DISTINCT column INTO tableB FROM tableA
It's going to insert into whatever column(s) are specified in the select list, so you would need to alias your select values if you need to insert into columns of tableB that aren't in tableA.
SELECT INTO
Try the following...
INSERT INTO tableB (column)
Select DISTINCT(tableA.column)
FROM tableA
The goal would be to select a distinct data set and then insert that data into a specific column of a new table.
I don't know what the schema of tableB is... if table B already exists and there is no unique constraint on the column you can do as any of the others suggest here....
INSERT INTO tableB (column)Select DISTINCT(tableA.column)FROM tableA
but if you have a unique constraint on table B and it already exists you'll have to exclude those values already in table B...
INSERT INTO tableB (column)
Select DISTINCT(tableA.column)
FROM tableA
WHERE tableA.column NOT IN (SELECT /* NOTE */ tableB.column FROM tableB)
-- NOTE: Remember if there is a unique constraint you don't need the more
-- costly form of a "SELECT DISTICT" in this subquery against tableB
-- This could be done in a number of different ways - this is just
-- one version. Best version will depend on size of data in each table,
-- indexes available, etc. Always prototype different ways and measure perf.

Compare unique values from two mysql tables

I have two mysql tables: TableA has 10,000 records TableB has 2,000 records.
I want to copy the 8,000 unique records from TableA into TableB ignoring the 2,000 in TableB which have already been copied.
If uniqueness is determined by PRIMARY KEY constraint or UNIQUE constraint, then you can use INSERT IGNORE:
INSERT IGNORE INTO TableB SELECT * FROM TableA;
The rows that are duplicates and that conflict with rows already in TableB will be silently skipped and the other 8,000 rows should be inserted.
See the docs on INSERT for more details.
If you need to do this in PHP, read about the array_diff_key() function. Store your arrays with the primary key values as the key of the array elements. No guarantees for the performance of this PHP function on such large arrays, though!
Use the INSERT INTO syntax:
INSERT INTO TABLE_B
SELECT *
FROM TABLE_A a
WHERE NOT EXISTS(SELECT NULL
FROM TABLE_B b
WHERE b.column = a.column)
You'll need to update the WHERE b.column = a.column) to satisfy however you determine that a record already exists in TABLE_B.
What about something like this :
insert into TableB
select *
from Table A
where not exists (
select 1
from TableB
where TableB.id = TableA.id
)
Or, if the entries in table B are "not unique" because of their primary key, an insert ignore might do the trick, I suppose.