Basic INSERT
INSERT INTO item_tags (item_id, tag_id)
SELECT p.item_id, t.id
FROM (SELECT item_id FROM properties WHERE name LIKE 'body') p
, (SELECT id FROM tags WHERE name ILIKE '%hoax%') t
Where the comma (,
) in the FROM clause is short notation for CROSS JOIN
.
That's building on your assertion that the second query on tags
...
returns 1 row of tag_id
You get a Cartesian Product from a CROSS JOIN
, that's n*m combinations.
If both sides of the join return more than one row, they multiply each other.
If either side does not return a row, the overall result is no row and nothing happens.
If you want neither of those effects, one side must return at least one row, and the other side exactly one row.
For your specific combination you can also use a nested subselect:
INSERT INTO item_tags (item_id, tag_id)
SELECT item_id
, (SELECT id FROM tags WHERE name ILIKE '%hoax%') AS tag_id -- single result!
FROM properties
WHERE name LIKE 'body';
The subtle difference: This inserts all rows returned from the outer SELECT
, even if the subselect on tags
returns no row, which would be converted to NULL
for tag_id
.
Bulk INSERT
To deal with lots of such inserts at once, you would use a largely modified query. But the same rules as for the first query above apply for cardinalities in both joined tables.
INSERT INTO item_tags (item_id, tag_id)
SELECT p.item_id, t.id
FROM (
VALUES
('body', 'hoax')
, ('body2', 'fun')
, ('body3', 'love')
) AS it(item, tag)
JOIN properties p ON p.name LIKE it.item
JOIN tags t ON t.name ILIKE ('%' || it.tag ||'%');
You see the logic, right? Personally, I call this a "CROSS JOIN
by proxy".
INSERT INTO item_tags (item_id, tag_id) SELECT ...
Just write the appropriate select query that combines the two you have into a 2 column select.INSERT INTO item_tags (item_id, tag_id) select * from (select item_id from properties where name like 'body') a, ( select id as tag_id from tags where name ilike '%hoax%') b;