My data looks like this:
TableA
- id INT
- is_in_table_b BOOL
TableB
- id INT
- table_a_id INT
I accidentally wiped out the 'is_in_table_b' BOOL on my dev machine while reorganizing the data structures, and I forgot how I created it. It's just a shortcut for some dev benchmarks.
All the "UPATE ... FROM ...." variations I tried are setting everything as "true" based on a the join. I can't remember if I originally had a CAST in this.
Does anyone know of a simple , elegant way to accomplish this? I just want to set is_in_table_b to True if the TableA.id appears in TableB.table_a_id. I know some non-elegant ways with inner queries, but I want to remember the more-correct ways to do this. I'm positive I had this done in an "Update From" originally.
This one should be simple enough:
UPDATE tableA SET
is_in_table_b = exists (select 1 FROM tableB WHERE table_a_id=tableA.id);
yeah, do a JOIN between the tables for an UPDATE.
the setup:
CREATE TABLE table_a (
id int not null auto_increment primary key,
is_in_b boolean
);
CREATE TABLE table_b (
table_a_id int
);
-- create some test data in table_a;
INSERT INTO table_a (is_in_b) VALUES (FALSE), (FALSE), (FALSE);
INSERT INTO table_a (is_in_b) SELECT FALSE
FROM table_a a1
JOIN table_a a2
JOIN table_a a3;
-- and create a subset of matching data in table_a;
INSERT INTO table_b (table_a_id)
SELECT id FROM table_a ORDER BY RAND() limit 5;
now the answer:
UPDATE table_a
JOIN table_b ON table_a_id = table_a.id
SET is_in_b = TRUE;
See the results with
SELECT * from table_b;
SELECT * FROM table_a WHERE is_in_b;
Works on http://sqlfiddle.com/#!2/8afc0/1 - should work in Postgres too I think.
Consider to drop that redundant column altogether and use a view or a "generated column" instead (with the EXISTS expression provided by #Daniel). Details under this related question:
Store common query as column?
Just be sure to have an index on TableB.table_a_id.
Related
I have two tables:
table_a with fields item_id,rank, and 50 other fields.
table_b with fields item_id, and the same 50 fields as table_a
I need to write a SELECT query that adds the rows of table_b to table_a but with rank set to a specific value, let's say 4.
Currently I have:
SELECT * FROM table_a
UNION
SELECT item_id, 4 rank, field_1, field_2, ...
How can I join the two tables together without writing out all of the fields and without using an INSERT query?
EDIT:
My idea is to join table_b to table_a somehow with the rank field remaining empty, then simply replace the null rank fields. The rank field is never null, but item_id can be duplicated and table_a may have item_id values that are not in table_b, and vice-versa.
I am not sure I understand why you need this, but you can use jsonb functions:
select (jsonb_populate_record(null::table_a, row)).*
from (
select to_jsonb(a) as row
from table_a a
union
select to_jsonb(b) || '{"rank": 4}'
from table_b b
) s
order by item_id;
Working example in rextester.
I'm pretty sure I've got it. The predefined rank column can be inserted into table_b by joining to the subset of itself with only the columns left of the column behind which you want to insert.
WITH
_leftcols AS ( SELECT item_id, 4 rank FROM table_b ),
_combined AS ( SELECT * FROM table_b JOIN _leftcols USING (item_id) )
SELECT * FROM _combined
UNION
SELECT * FROM table_a
As the title suggests, I need to change my update and join statements into insert statements. How I would do this while incorporating SET from the UPDATE statements?
Update statement:
UPDATE tableA
SET A = tableB.A
FROM tableB
JOIN tableC ON tableB.C = tableC.C
WHERE tableC.D = tableA.D
Your tables are empty, thus tableC.D = tableA.D wouldn't provide anything.
May it be you are looking for something like this?:
INSERT INTO tableA (A)
SELECT DISTINCT tb.A
FROM tableB tb
JOIN tableC tc ON tb.C = tc.C
Or perhaps including the D column:
INSERT INTO tableA (A, D)
SELECT DISTINCT tb.A, tc.D
FROM tableB tb
JOIN tableC tc ON tb.C = tc.C
Note the use of DISTINCT here to dispense duplicate records.
Generally, it is good practice to include all the column names in the INSERT statement. And you can remove WHERE clause by JOINing tableA to tableC. But just the simple answer for your question would be:
INSERT INTO tableA (<col name you want to update>)
VALUES (SELECT <one value> FROM tableB JOIN tableC ON tableB.C = tableC.C JOIN tableA ON tableC.D = tableA.D
);
I have two tables which i wish to combine. However, there is a field in both tables that should have the same value in the second table the second tables record should be excluded.
These are a MSSQL 2012 tables.
The only way i can think of is something nasty like this.
Select A, B
from Tab1
Union
Select C, D
from Tab2
where Tab2.c not in (Select A from Tab1)
It looks relatively clean in my example but the selects for Tab1 and tab2 have long and complex where clauses and i would need to duplicated that in the "not in" select statement.
I've seen other solutions but not in MSSQL. Any one out there have a better example ?
Thanks
well in t-sql i use this kind of code
USE tempdb
GO
CREATE TABLE StudentDetails
(
StudentID INTEGER PRIMARY KEY,
StudentName VARCHAR(15)
)
GO
INSERT INTO StudentDetails
VALUES(1,'SMITH')
INSERT INTO StudentDetails
VALUES(2,'ALLEN')
INSERT INTO StudentDetails
VALUES(3,'JONES')
INSERT INTO StudentDetails
VALUES(4,'MARTIN')
INSERT INTO StudentDetails
VALUES(5,'JAMES')
GO
CREATE TABLE StudentTotalMarks
(
StudentID INTEGER REFERENCES StudentDetails,
StudentMarks INTEGER
)
GO
INSERT INTO StudentTotalMarks
VALUES(1,230)
INSERT INTO StudentTotalMarks
VALUES(2,255)
INSERT INTO StudentTotalMarks
VALUES(3,200)
GO
-- Select from Table
SELECT *
FROM StudentDetails
GO
SELECT *
FROM StudentTotalMarks
GO
-- Merge Statement
MERGE StudentTotalMarks AS stm
USING (SELECT StudentID,StudentName FROM StudentDetails) AS sd
ON stm.StudentID = sd.StudentID
WHEN MATCHED AND stm.StudentMarks > 250 THEN DELETE
WHEN MATCHED THEN UPDATE SET stm.StudentMarks = stm.StudentMarks + 25
WHEN NOT MATCHED THEN
INSERT(StudentID,StudentMarks)
VALUES(sd.StudentID,25);
GO
-- Select from Table
SELECT *
FROM StudentDetails
GO
SELECT *
FROM StudentTotalMarks
GO
-- Clean up
DROP TABLE StudentDetails
GO
DROP TABLE StudentTotalMarks
GO
The Merge Join performs very well and the following result is obtained.
http://www.pinaldave.com/bimg/MergeStatement.gif
Hope this helps
I have two tables, where they have the same ID name (I cannot change the way the tables are designed) and I'm trying to query table2's ID, how would I do this when they are joined?
create table table1(
id integer, -- PG: serial
description MediumString not null,
primary key (id)
);
create table table2 (
id integer, -- PG: serial
tid references table1(id),
primary key (id)
);
So basically when they're joined, two columns will have the same name "id" if I do the following query
select * from table1
join table2 on table1.id = table2.tid;
Alias the columns if you want both "id"s
SELECT table1.id AS id1, table2.id AS id2
FROM table1...
If you want to query all * on both tables but still be able to reference a specific id you can do that too, you will end up with duplicate id columns that you probably won't use, but in some situations if you really need all the data, it's worth it.
select table1.*, table2.*, table1.id as 'table1.id', table2.id as 'table2.id'
from ...
You cannot select it using select *.
try this :
select table1.id, table1.description, table2.id, table2.tid
from table1
inner join table2
on table1.id = table2.tid
Scenario:
Let's say I have two tables, TableA and TableB. TableB's primary key is a single column (BId), and is a foreign key column in TableA.
In my situation, I want to remove all rows in TableA that are linked with specific rows in TableB: Can I do that through joins? Delete all rows that are pulled in from the joins?
DELETE FROM TableA
FROM
TableA a
INNER JOIN TableB b
ON b.BId = a.BId
AND [my filter condition]
Or am I forced to do this:
DELETE FROM TableA
WHERE
BId IN (SELECT BId FROM TableB WHERE [my filter condition])
The reason I ask is it seems to me that the first option would be much more effecient when dealing with larger tables.
Thanks!
DELETE TableA
FROM TableA a
INNER JOIN TableB b
ON b.Bid = a.Bid
AND [my filter condition]
should work
I would use this syntax
Delete a
from TableA a
Inner Join TableB b
on a.BId = b.BId
WHERE [filter condition]
Yes you can. Example :
DELETE TableA
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]
Was trying to do this with an access database and found I needed to use a.* right after the delete.
DELETE a.*
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]
It's almost the same in MySQL, but you have to use the table alias right after the word "DELETE":
DELETE a
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]
The syntax above doesn't work in Interbase 2007. Instead, I had to use something like:
DELETE FROM TableA a WHERE [filter condition on TableA]
AND (a.BId IN (SELECT a.BId FROM TableB b JOIN TableA a
ON a.BId = b.BId
WHERE [filter condition on TableB]))
(Note Interbase doesn't support the AS keyword for aliases)
I'm using this
DELETE TableA
FROM TableA a
INNER JOIN
TableB b on b.Bid = a.Bid
AND [condition]
and #TheTXI way is good as enough but I read answers and comments and I found one things must be answered is using condition in WHERE clause or as join condition. So I decided to test it and write an snippet but didn't find a meaningful difference between them. You can see sql script here and important point is that I preferred to write it as commnet because of this is not exact answer but it is large and can't be put in comments, please pardon me.
Declare #TableA Table
(
aId INT,
aName VARCHAR(50),
bId INT
)
Declare #TableB Table
(
bId INT,
bName VARCHAR(50)
)
Declare #TableC Table
(
cId INT,
cName VARCHAR(50),
dId INT
)
Declare #TableD Table
(
dId INT,
dName VARCHAR(50)
)
DECLARE #StartTime DATETIME;
SELECT #startTime = GETDATE();
DECLARE #i INT;
SET #i = 1;
WHILE #i < 1000000
BEGIN
INSERT INTO #TableB VALUES(#i, 'nameB:' + CONVERT(VARCHAR, #i))
INSERT INTO #TableA VALUES(#i+5, 'nameA:' + CONVERT(VARCHAR, #i+5), #i)
SET #i = #i + 1;
END
SELECT #startTime = GETDATE()
DELETE a
--SELECT *
FROM #TableA a
Inner Join #TableB b
ON a.BId = b.BId
WHERE a.aName LIKE '%5'
SELECT Duration = DATEDIFF(ms,#StartTime,GETDATE())
SET #i = 1;
WHILE #i < 1000000
BEGIN
INSERT INTO #TableD VALUES(#i, 'nameB:' + CONVERT(VARCHAR, #i))
INSERT INTO #TableC VALUES(#i+5, 'nameA:' + CONVERT(VARCHAR, #i+5), #i)
SET #i = #i + 1;
END
SELECT #startTime = GETDATE()
DELETE c
--SELECT *
FROM #TableC c
Inner Join #TableD d
ON c.DId = d.DId
AND c.cName LIKE '%5'
SELECT Duration = DATEDIFF(ms,#StartTime,GETDATE())
If you could get good reason from this script or write another useful, please share. Thanks and hope this help.
Let's say you have 2 tables, one with a Master set (eg. Employees) and one with a child set (eg. Dependents) and you're wanting to get rid of all the rows of data in the Dependents table that cannot key up with any rows in the Master table.
delete from Dependents where EmpID in (
select d.EmpID from Employees e
right join Dependents d on e.EmpID = d.EmpID
where e.EmpID is null)
The point to notice here is that you're just collecting an 'array' of EmpIDs from the join first, the using that set of EmpIDs to do a Deletion operation on the Dependents table.
In SQLite, the only thing that work is something similar to beauXjames' answer.
It seems to come down to this
DELETE FROM table1 WHERE table1.col1 IN (SOME TEMPORARY TABLE);
and that some temporary table can be crated by SELECT and JOIN your two table which you can filter this temporary table based on the condition that you want to delete the records in Table1.
The simpler way is:
DELETE TableA
FROM TableB
WHERE TableA.ID = TableB.ID
DELETE FROM table1
where id IN
(SELECT id FROM table2..INNER JOIN..INNER JOIN WHERE etc)
Minimize use of DML queries with Joins. You should be able to do most of all DML queries with subqueries like above.
In general, joins should only be used when you need to SELECT or GROUP by columns in 2 or more tables. If you're only touching multiple tables to define a population, use subqueries. For DELETE queries, use correlated subquery.
You can run this query:
DELETE FROM TableA
FROM
TableA a, TableB b
WHERE
a.Bid=b.Bid
AND
[my filter condition]