Difference between delete statements - sql

DELETE a
FROM TableA a
JOIN TableB b ON a.Field1 = b.Field1 AND a.Field2 = b.Field2;
vs.
DELETE
FROM TableA
WHERE Field1 IN (
SELECT Field1
FROM TableB
) AND Field2 IN (
SELECT Field2
FROM TableB
);

The logical conditions of the two statements are different.
The first statement will delete any row in TableA if both it's Field1 and Field2 correspond to the equivalent columns of a row in TableB.
The second statement will delete any row in TableA if the value of Field1 exists in Field1 of TableB, and the value of Field2 exists in Field2 of TableB - but that doesn't have to be in the same row.
It's easy to see the difference if you change the delete to select.
Here's an example. First, create and populate sample tables (Please save us this step in your future questions):
CREATE TABLE A
(
AInt int,
AChar char(1)
);
CREATE TABLE B
(
BInt int,
BChar char(1)
);
INSERT INTO A (AInt, AChar) VALUES
(1, 'a'), (2, 'a'), (3, 'a'),
(1, 'b'), (2, 'b'), (3, 'b');
INSERT INTO B (BInt, BChar) VALUES
(1, 'a'),
(2, 'b'),
(3, 'c');
The statements (translated to select statements):
SELECT A.*
FROM A
JOIN B
ON AInt = BInt AND AChar = BChar;
SELECT *
FROM A
WHERE AInt IN (
SELECT BInt
FROM B
) AND AChar IN (
SELECT BChar
FROM B
);
Results:
AInt AChar
1 a
2 b
AInt AChar
1 a
2 a
3 a
1 b
2 b
3 b
And you can see a live demo on DB<>Fiddle

Related

SQL db2 update query for multiple rows

I am updating records by the following queries:
update tableA set Quantity=
(select count(*) from table B where ID=x)
where ID=x
update tableA set Quantity=
(select sum(Stock) from table C where ID=y)
where ID=y
Example(Corrected):
All the ID from tableA are divided into 2 tables: TableB and TableC. I have to update the quantity field of TableA with count of TableB ( if ID.TableA is in TableB) and update the quantity field of TableA with sun(stock) of TableC ( if ID.TableA is in TableC)
There are 500k IDs to be updated like this. I was wondering how it can be done without having to execute 500k queries.
EDIT: I am fetching the count of rows from TableB, count is not a column for TableB.
Any help will be appreciated,TIA!
The names of your tables and columns are not 100% clear to me from your question, so I'm guessing a little bit about them. Correct if needed:
update tablea a set quantity = case
when (select count(*) from tableb where b.id = a.id) is not null then
(select count(*) from tableb b where b.id = a.id)
else
(select sum(stock) from tablec c where c.id = a.id)
end
declare global temporary table tablea(id int not null, quantity int) with replace on commit preserve rows not logged;
declare global temporary table tableb(id int not null) with replace on commit preserve rows not logged;
declare global temporary table tablec(id int not null, stock int) with replace on commit preserve rows not logged;
insert into session.tablea values (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0);
insert into session.tableb values 1, 1, 1, 2, 2, 3;
insert into session.tablec values (4, 3), (5, 2), (5, 2), (5, 1), (6, 3), (6, 4);
update session.tableA a
set Quantity=coalesce(
nullif((select count(*) from session.tableb b where b.ID=a.ID), 0)
, (select sum(stock) from session.tablec c where c.ID=a.ID)
);
select * from session.tableA;
You can use a correlated subquery:
update tableA
set Quantity = (select count(*) from table B where B.ID = A.ID)

How to know the column name from a table based on the column values

I am working in Informix and I want to know if there is a simple way to know the tabname/colname by its possible column values.
For example:
table1
Register 1
==========
id 1
col1 3
col2 Y
Register 2
==========
id 2
col1 43
col2 X
Register 3
==========
id 2
col1 0
col2 Z
Register 4
==========
id 2
col1 23
col2 F
table2
Register 1
==========
id 1
col1 X
col2 Y
Register 2
==========
id 2
col1 X
col2 X
Register 3
==========
id 2
col1 Z
col2 Z
Register 4
==========
id 2
col1 X
col2 X
table3
Register 1
==========
id 1
col1 ASX
With this database, if I want to know the colnames and their related tabnames of the database that contain X, Y and Z (amoung other values).
It could be something like this:
select tabname, colname
where ('X','Y','Z') in colnamevalues --this has been invented by me
And this should return the following values:
table1.col2
table2.col1
table2.col2
--Note that the columns fetched contains also other values
--different from 'X', 'Y' and 'Z' but T didn't fix in this case
--the whole list of values, only some of them
I have queried for other Q&A but all of them look to use some functions of other databases such as Oracle or SQL Server and I don't understand them very well.
You can get all the tables that exist on a database by querying the systables:
SELECT tabname
FROM systables
WHERE tabtype = 'T' --get only tables
AND tabid > 99; --skip catalog tables
You can join it to the syscolumns table to get the columns:
SELECT t.tabname, c.colname
FROM systables t
INNER JOIN syscolumns c ON (c.tabid = t.tabid)
WHERE t.tabtype = 'T' AND t.tabid > 99;
And if you know the type of values you can even filter it. Example if you're looking for "strings":
SELECT t.tabname, c.colname
FROM systables t
INNER JOIN syscolumns c ON (c.tabid = t.tabid)
WHERE t.tabtype = 'T' AND t.tabid > 99
AND MOD(c.coltype,256) IN (
0, --CHAR
13, --VARCHAR
15, --NCHAR
16, --NVARCHAR
40, --LVARCHAR
43 --LVARCHAR
);
The next example works, but it really should be optimized and bullet proof, but can get you kick off.
When I have time I get another look at it and check what can be optimized and put some error handling.
Another way to do it is scripting, what OS are you running?
Schema creation:
CREATE TABLE tab1(
id INT,
col1 CHAR(3),
col2 CHAR(3)
);
INSERT INTO tab1 VALUES (1, 3, 'Y');
INSERT INTO tab1 VALUES (2, 43, 'X');
INSERT INTO tab1 VALUES (2, 0, 'Z');
INSERT INTO tab1 VALUES (2, 23, 'F');
CREATE TABLE tab2(
id INT,
col1 CHAR(3),
col2 CHAR(3)
);
INSERT INTO tab2 VALUES (1, 'X', 'Y');
INSERT INTO tab2 VALUES (2, 'X', 'X');
INSERT INTO tab2 VALUES (2, 'Z', 'Z');
INSERT INTO tab2 VALUES (2, 'X', 'X');
CREATE TABLE tab3(
id INT,
col1 CHAR(3)
);
INSERT INTO tab3 VALUES (1, 'ASX');
Sample function:
CREATE FUNCTION get_columns()
RETURNING LVARCHAR(257) AS col;
DEFINE stmt VARCHAR(255);
DEFINE tab_name VARCHAR(128,0);
DEFINE tab_id INTEGER;
DEFINE col_name VARCHAR(128,0);
DEFINE o_tname VARCHAR(128,0);
DEFINE o_cname VARCHAR(128,0);
CREATE TEMP TABLE out_table(
t_name VARCHAR(128,0),
c_name VARCHAR(128,0)
);
CREATE TEMP TABLE tab_v (
col1 VARCHAR(255)
);
INSERT INTO tab_v VALUES ('X');
INSERT INTO tab_v VALUES ('Y');
INSERT INTO tab_v VALUES ('Z');
FOREACH tables FOR
SELECT tabname, tabid
INTO tab_name, tab_id
FROM systables
WHERE tabid > 99 AND tabtype = 'T'
FOREACH column FOR
SELECT colname
INTO col_name
FROM syscolumns
WHERE tabid = tab_id
AND MOD(coltype,256) IN (
0, --CHAR
13, --VARCHAR
15, --NCHAR
16, --NVARCHAR
40, --LVARCHAR
43 --LVARCHAR
)
LET stmt = "INSERT INTO out_table "||
"SELECT '"||tab_name||"', '"||col_name||"' "||
"FROM "||tab_name||" "||
"WHERE EXISTS (SELECT 1 FROM tab_v v WHERE v.col1 = "||col_name||");";
EXECUTE IMMEDIATE stmt;
END FOREACH
END FOREACH
FOREACH out FOR
SELECT UNIQUE t_name, c_name
INTO o_tname, o_cname
FROM out_table
RETURN o_tname||"."||o_cname WITH RESUME;
END FOREACH
DROP TABLE out_table;
DROP TABLE tab_v;
END FUNCTION;
EXECUTE FUNCTION get_columns();

Joining tables on columns with different names but produce single column in result

I'm not sure how to concisely formulate question to describe a problem I would like to solve.
I have two following tables:
Table 1
[idA] [numA]
NULL 8
1 10
2 15
3 16
Table 2
[idB] [numB]
2 14
3 30
4 32
Now, I'm not sure how to formulate T-Sql query to produce following result:
[id] [numA] [numB]
NULL 8 0
1 10 0
2 15 14
3 16 30
4 0 32
Are there any suggestions on how to solve this?
UPDATE:
Would there be any problems with #AdaTheDev's script if there was one more table (idC, numC) to join? In that case what would be the best solution? The thing is I have 15 of them to join into one table and they should be grouped by id and have 15 corresponding numX columns.
Something like this, should do it
SELECT ISNULL(t1.idA, t2.idB) AS id,
ISNULL(t1.numA, 0) AS numA,
ISNULL(t2.NumB, 0) AS numB
FROM table1 t1
FULL OUTER JOIN table2 t2 ON t1.idA = t2.idB OR t1.ida IS NULL AND t2.idb IS NULL
Update
Note I've added an OR condition to the join to handle the case where idA and idB are NULL, to give a single result
Full test script (with added NULL id record in table2):
DECLARE #Table1 TABLE (ida integer, numA INTEGER)
DECLARE #Table2 TABLE (idb integer, numb INTEGER)
INSERT #Table1 ([ida], [numA])
VALUES (NULL, 8), (1, 10), (2, 15), (3, 16)
INSERT #Table2 ([idb], [numb])
VALUES (NULL, 9), (2, 14), (3, 30), (4, 32)
SELECT ISNULL(t1.idA, t2.idB) AS id,
ISNULL(t1.numA, 0) AS numA,
ISNULL(t2.NumB, 0) AS numB
FROM #table1 t1
FULL OUTER JOIN #table2 t2 ON t1.idA = t2.idB OR t1.ida IS NULL AND t2.idb IS NULL
DECLARE #table1 AS TABLE (idA INT, numA INT)
DECLARE #table2 AS TABLE (idB INT, numB INT)
INSERT INTO #table1
VALUES
(NULL, 8),
(1, 10),
(2, 15),
(3, 16)
INSERT INTO #table2
VALUES
(2, 14),
(3, 30),
(4, 32)
SELECT COALESCE(ida, idb) AS id, ISNULL(numa, 0) AS numa, ISNULL(numb, 0) AS numb
FROM #table1
FULL OUTER JOIN #table2 ON ida = idb
Is this what you're after?
select tableA.idA as Id, tableA.numA as numA, tableB.numB as numB
from tableA
inner join tableB on tableA.Id = tableB.Id

How to get a fixed amount of results per row?

How can I build a query with this format with a sqlite3 database?
CREATE TABLE sample (integer foo);
INSERT INTO sample VALUES (1);
...
INSERT INTO sample VALUES (10);
Format of the result
1,2,3
4,5,6
7,8,9
10
You'll have to add some criteria to group them:
CREATE TABLE sample (integer foo, char(1) bar);
INSERT INTO sample VALUES
(1, 'a'), (2, 'a'), (3, 'a'), (4, 'b'), (5, 'b'), (6, 'b'), (7, 'c') ...;
SELECT GROUP_CONCAT(foo ORDER BY foo, ',')
FROM sample
GROUP BY bar
Edit:
Try this:
select group_concat(foo) from (
select s1.foo, (count(*) - 1) / 3 grp from sample s1
join sample s2 on s1.rowid >= s2.rowid
group by s1.rowid
) final
group by grp
This might not be the best solution (and has some edge cases---if you have a 3 value that is not null), and can probably be put into one query, but I needed the RowId to join on. It should do the trick, though:
CREATE TEMP TABLE split1 (foo1 int);
CREATE TEMP TABLE split2 (foo2 int);
CREATE TEMP TABLE split3 (foo3 int);
INSERT INTO split1
SELECT foo FROM sample WHERE foo % 3 = 1 ORDER BY foo
INSERT INTO split2
SELECT foo FROM sample WHERE foo % 3 = 2 ORDER BY foo
INSERT INTO split3
SELECT foo FROM sample WHERE foo % 3 = 0 ORDER BY foo
SELECT
CASE
WHEN foo2 IS NULL THEN foo1
WHEN foo3 IS NULL THEN foo1||','||foo2
ELSE foo1||','||foo2||','||foo3
END
FROM split1
LEFT JOIN split2
ON split1.RowId = split2.RowId
LEFT JOIN split3
ON split2.RowId = split3.RowId

SQL script to aggregate column values

i'd appreciate some help putting together a sql script to copy data from one table to another. essentially what i need to do for each row in the source table is aggregate the column values and store them into a single column in the target table.
TableA: ID, ColumnA, ColumnB, ColumnC
TableB: Identity, ColumnX
so, ColumnX needs to be something like 'ColumnA, ColumnB, ColumnC'.
in addition though, i need to keep track of each TableA.ID -> SCOPE_IDENTITY() mapping in order to update a third table.
thanks in advance!
EDIT: TableA.ID is not the same as TableB.Identity. TableB.Identity will return a new identity value on insert. so either i need to store the mapping in a temp table or update TableC with each insert into TableB.
Here is a row-by-row processing example. This will provide you the results in a way where you can process each row at a time. Or you can use TableC at the end and do whatever processing you need to do.
However, it would be a lot faster if you added an extra column to TableB (Called TableA_ID) and just INSERTED the result into it. You would have instant access to TableA.ID and TableB.Identity. But without knowing your exact situation, this may not be feasible. (But you could always add the column and then drop it afterwards!)
USE tempdb
GO
CREATE TABLE TableA (
ID int NOT NULL PRIMARY KEY,
ColumnA varchar(10) NOT NULL,
ColumnB varchar(10) NOT NULL,
ColumnC varchar(10) NOT NULL
)
CREATE TABLE TableB (
[Identity] int IDENTITY(1,1) NOT NULL PRIMARY KEY,
ColumnX varchar(30) NOT NULL
)
CREATE TABLE TableC (
TableA_ID int NOT NULL,
TableB_ID int NOT NULL,
PRIMARY KEY (TableA_ID, TableB_ID)
)
GO
INSERT INTO TableA VALUES (1, 'A', 'A', 'A')
INSERT INTO TableA VALUES (2, 'A', 'A', 'B')
INSERT INTO TableA VALUES (3, 'A', 'A', 'C')
INSERT INTO TableA VALUES (11, 'A', 'B', 'A')
INSERT INTO TableA VALUES (12, 'A', 'B', 'B')
INSERT INTO TableA VALUES (13, 'A', 'B', 'C')
INSERT INTO TableA VALUES (21, 'A', 'C', 'A')
INSERT INTO TableA VALUES (22, 'A', 'C', 'B')
INSERT INTO TableA VALUES (23, 'A', 'C', 'C')
GO
-- Do row-by-row processing to get the desired results
SET NOCOUNT ON
DECLARE #TableA_ID int
DECLARE #TableB_Identity int
DECLARE #ColumnX varchar(100)
SET #TableA_ID = 0
WHILE 1=1 BEGIN
-- Get the next row to process
SELECT TOP 1
#TableA_ID=ID,
#ColumnX = ColumnA + ColumnB + ColumnC
FROM TableA
WHERE ID > #TableA_ID
-- Check if we are all done
IF ##ROWCOUNT = 0
BREAK
-- Insert row into TableB
INSERT INTO TableB (ColumnX)
SELECT #ColumnX
-- Get the identity of the new row
SET #TableB_Identity = SCOPE_IDENTITY()
-- At this point, you have #TableA_ID and #TableB_Identity.
-- Go to town with whatever extra processing you need to do
INSERT INTO TableC (TableA_ID, TableB_ID)
SELECT #TableA_ID, #TableB_Identity
END
GO
SELECT * FROM TableC
GO
SELECT * FROM TableA
ID ColumnA ColumnB ColumnC
----------- ---------- ---------- ----------
1 A A A
2 A A B
3 A A C
11 A B A
12 A B B
13 A B C
21 A C A
22 A C B
23 A C C
SELECT * FROM TableB
Identity ColumnX
----------- ------------------------------
1 AAA
2 AAB
3 AAC
4 ABA
5 ABB
6 ABC
7 ACA
8 ACB
9 ACC
SELECT * FROM TableC
TableA_ID TableB_ID
----------- -----------
1 1
2 2
3 3
11 4
12 5
13 6
21 7
22 8
23 9
Assuming:
TableB exists
INSERT INTO TableB (ColumnX)
SELECT [TableA]![ColumnA]+","+[TableA]![ColumnB]+","+[TableA]![ColumnC] AS ColumnX
FROM TableA;