sql query: column by id multiple times - sql

SQL newb here.
I am having troubles to create a select statement.
I have one table REF with an id and a value v;
+-----+----+
| REF | |
+-----+----+
| ID | V |
| 1 | 10 |
| 2 | 20 |
| 3 | 30 |
| 4 | 40 |
| 5 | 50 |
| 6 | 60 |
| 7 | 70 |
+-----+----+
in a second table IND i have three columns with id-values;
+-----+-----+-----+
|IND | | |
|-----|-----|-----|
| ID1 | ID2 | ID3 |
| 1 | 2 | |
| | 3 | 4 |
| 5 | | |
| 6 | | 7 |
I want to receive the value of REF.v accordinlgly in each of the three columns (Table RES); the ids are distinct, there is no overlapping in between.
+-----+-----+-----+
| RES | | |
+-----+-----+-----+
| ID1 | ID2 | ID3 |
| 10 | 20 | |
| | 30 | 40 |
| 50 | | |
| 60 | | 70 |
+-----+-----+-----+

You can query your IND table, using three subqueries to retrieve the value linked to used id
Try this:
SELECT
(SELECT V FROM REF WHERE REF.ID = IND.ID1) AS V_ID1,
(SELECT V FROM REF WHERE REF.ID = IND.ID2) AS V_ID2,
(SELECT V FROM REF WHERE REF.ID = IND.ID3) AS V_ID3
FROM IND
UPDATE
About two proposed solutions (LEFT OUTER JOINs Vs SUBQUERIES)
I've tried on Sql Fiddle under Postgres 9.6 engine.
Times are the same but execution plan about LEFT OUTER JOIN is more complex
You can see SqlFiddle SUBQUERIES and SqlFiddle LEFT OUTER JOINs

SELECT ref1.V AS RefV1, ref2.V AS RefV2, ref3.V AS RefV3
FROM IND i
LEFT OUTER JOIN ref ref1
ON ref1.ID = i.ID1
LEFT OUTER JOIN ref ref2
ON ref2.ID = i.ID2
LEFT OUTER JOIN ref ref3
ON ref3.ID = i.ID3
You connect the reference table three times, using a left outer join, which lets the reference table not match the IND table, resulting in nulls where you had missing IDs. Then you select the v value from each of these joined tables, being sure to alias it, so you can tell them apart.

Related

Joining table on two columns only joins it on a single

How do I correctly join a table on two columns. My issue is that the result is not correct as it only joins on a single column.
This question started of in this other question: SQL query returns product of results instead of sum . I am creating a new question as there is an other issue I am trying to solve.
I join a table of materials on a table which contains multiple supply and disposal movements. Each movement references a material id. I would like to join the material on each movement.
My query:
SELECT supply_material_refer, disposal_material_refer, material_id, material_name
FROM "construction_sites"
JOIN projects ON construction_sites.project_refer = projects.project_id
JOIN addresses ON construction_sites.address_refer = addresses.address_id
cross join lateral ( select *
from (select row_number() over () as rn, *
from supplies
where supplies.supply_project_refer = projects.project_id) as supplies
full join (select row_number() over () as rn, *
from disposals
where disposals.disposal_project_refer = projects.project_id
) as disposals
on (supplies.rn = disposals.rn)
) as combined
LEFT JOIN materials material ON combined.disposal_material_refer = material.material_id
OR combined.supply_material_refer = material.material_id
WHERE (projects.project_name = 'Project 15')
ORDER BY construction_site_id asc;
The result of the query:
+-----------------------+-------------------------+-------------+---------------+
| supply_material_refer | disposal_material_refer | material_id | material_name |
+-----------------------+-------------------------+-------------+---------------+
| 1 | 1 | 1 | Materialtest |
| 2 | 1 | 1 | Materialtest |
| 2 | 1 | 2 | Dirt |
| 1 | 1 | 1 | Materialtest |
| 2 | 1 | 1 | Materialtest |
| 2 | 1 | 2 | Dirt |
| 1 | (null) | 1 | Materialtest |
| 4 | (null) | 4 | Stones |
+-----------------------+-------------------------+-------------+---------------+
An example line I have issues with:
+------------------------+-------------------------+-------------+---------------+
| supply_material_refer | disposal_material_refer | material_id | material_name |
+------------------------+-------------------------+-------------+---------------+
| 2 | 1 | 1 | Materialtest |
+------------------------+-------------------------+-------------+---------------+
A prefered output would be like:
+------------------------+----------------------+-------------------------+------------------------+
| supply_material_refer | supply_material_name | disposal_material_refer | disposal_material_name |
+------------------------+----------------------+-------------------------+------------------------+
| 2 | Dirt | 1 | Materialtest |
+------------------------+----------------------+-------------------------+------------------------+
I have created a sqlfiddle with dummy data: http://www.sqlfiddle.com/#!17/863d78/2
To my understanding the solution would be to have a disposal_material column and and supply_material column for the material names. I do not know how I can achieve this goal though...
Thanks for any help!

SQL JOIN two table & show all rows for table A

I have a question about JOIN.
TABLE A | TABLE B |
-----------------------------------------|
PK | div | PK | div | val |
-----------------------------------------|
A | a | 1 | a | 10 |
B | b | 2 | a | 100 |
C | c | 3 | c | 9 |
------------------| 4 | c | 99 |
-----------------------
There are two tables something like above, and I have been trying to join two tables but I want to see all rows from TABLE A.
Something like
SELECT T1.PK, T1.div, T2.val
FROM A T1
LEFT OUTER JOIN B T2
ON T1.div = T2.div
and I want the result would look like this below.
PK | div | val |
-------------------------
A | a | 10 |
A | a | 100 |
B | null | null |
C | c | 9 |
C | c | 99 |
I have tried all JOINs I know but B doesn't appear because it doesn't exist. Is it possible to show all rows on TABLE A and just show null if it doesn't exists on TABLE B?
Thanks in advance!
If you change your query to
SELECT T1.PK, T2.div, T2.val
FROM A T1
LEFT OUTER JOIN B T2
ON T1.div = T2.div
(Note, that div comes from T2 here.), you'll get exactly the result posted (but maybe in a different order, add an ORDER BY clause if you want a specific order).
Your query as it stands will get you:
PK | div | val |
-------------------------
A | a | 10 |
A | a | 100 |
B | b | null |
C | c | 9 |
C | c | 99 |
(Note, that div is b for the row with the PK of B, not null.)
To get to your resultset, all you need to do is use T2.Div as that is the value that does not exist in the second table:
SELECT T1.PK, T2.div, T2.val
FROM A T1
LEFT OUTER JOIN B T2
ON T1.div = T2.div

Access Queries comparing two tables

I have two tables in Access, Table A and Table B:
Table MasterLockInsNew:
+----+-------+----------+
| ID | Value | Date |
+----+-------+----------+
| 1 | 123 | 12/02/13 |
| 2 | 1231 | 11/02/13 |
| 4 | 1265 | 16/02/13 |
+----+-------+----------+
Table InitialPolData:
+----+-------+----------+---+
| ID | Value | Date |Type
+----+-------+----------+---+
| 1 | 123 | 12/02/13 | x |
| 2 | 1231 | 11/02/13 | x |
| 3 | 1238 | 10/02/13 | y |
| 4 | 1265 | 16/02/13 | a |
| 7 | 7649 | 18/02/13 | z |
+----+-------+----------+---+
All I want are the rows from table B for IDs not contained in A. My current code looks like this:
SELECT Distinct InitialPolData.*
FROM InitialPolData
WHERE InitialPolData.ID NOT IN (SELECT Distinct InitialPolData.ID
from InitialPolData INNER JOIN
MasterLockInsNew
ON InitialPolData.ID=MasterLockInsNew.ID);
But whenever I run this in Access it crashes!! The tables are fairly large but I don't think this is the reason.
Can anyone help?
Thanks
or try a left outer join:
SELECT b.*
FROM InitialPolData b left outer join
MasterLockInsNew a on
b.id = a.id
where
a.id is null
Simple subquery will do.
select * from InitialPolData
where id not in (
select id from MasterLockInsNew
);
Try using NOT EXISTS:
SELECT Distinct i.*
FROM InitialPolData AS i
WHERE NOT EXISTS (SELECT 1
FROM MasterLockInsNew AS m
WHERE m.ID = i.ID)

PostgreSQL select all from one table and join count from table relation

I have two tables, post_categories and posts. I'm trying to select * from post_categories;, but also return a temporary column with the count for each time a post category is used on a post.
Posts
| id | name | post_category_id |
| 1 | test | 1 |
| 2 | nest | 1 |
| 3 | vest | 2 |
| 4 | zest | 3 |
Post Categories
| id | name |
| 1 | cat_1 |
| 2 | cat_2 |
| 3 | cat_3 |
Basically, I'm trying to do this without subqueries and with joins instead. Something like this, but in real psql.
select * from post_categories some-type-of-join posts, count(*)
Resulting in this, ideally.
| id | name | count |
| 1 | cat_1 | 2 |
| 2 | cat_2 | 1 |
| 3 | cat_3 | 1 |
Your help is greatly appreciated :D
You can use a derived table that contains the counts per post_category_id and left join it to the post_categories table
select p.*, coalesce(t1.p_count,0)
from post_categories p
left join (
select post_category_id, count(*) p_count
from posts
group by post_category_id
) t1 on t1.post_category_id = p.id
select post_categories.id, post_categories.name , count(posts.id)
from post_categories
inner join posts
on post_category_id = post_categories.id
group by post_categories.id, post_categories.name

Can I combine values from multiple rows in another table into multiple columns of one row using SQL?

I have two tables:
T1:
| M_ID | P_ID1 | P_ID2 | rest of T1 columns |
| 0 | 0 | 1 | ... |
| 1 | 2 | 3 | ... |
T2:
| P_ID | Type | A | B |
| 0 | 1 | a | e |
| 1 | 2 | b | f |
| 2 | 1 | c | g |
| 3 | 2 | d | h |
Now, I want to have a query that selects this:
| M_ID | P_1a | P_1b | P_2a | P_2b | rest of T1 columns |
| 0 | a | e | b | f | ... |
| 1 | c | g | c | h | ... |
So, in words: I want to select all columns from T1, but I want to replace P_ID1 with the columns from T2, where the P_ID is equal to P_ID1, and the type is 1, and basically the same for P_ID2.
I can obviously get the information I need with multiple queries, but I was wondering if there is a way that I can do this with one query. Any ideas?
I'm currently using SQL Server 2008r2, but I'd also be interested in solutions for other database software.
Thanks for the help!
Sure, you just need to use a join:
select T1.M_ID, t2_1.A as P_1a, t2_1.B as P_1b, t2_2.A as P_2a, t2_2.B as P_2b, ...
from T1, T2 t2_1, T2 t2_2
where T1.P_ID1 = t2_1.P_ID and T1.P_ID2 = t2_2.P_ID
basically we are joining T1 onto T2 twice, once for the P_1 values and a second time for the P_2 values. You need to alias T2 when you join it twice to distinguish between the two (that's what the t2_1 and t2_2 are - a means of distinguishing between the two instances of the joined T2).
This is the same as #John Pickup's solution only using modern join syntax:
select T1.M_ID, t2_1.A as P_1a, t2_1.B as P_1b, t2_2.A as P_2a, t2_2.B as P_2b, ...
from T1
join T2 t2_1 on T1.P_ID1 = t2_1.P_ID
join T2 t2_2 on T1.P_ID2 = t2_2.P_ID
I only post a seperate answer, as there is no code formatting in comments as you get told here