How to join with two tables simultaneously? - sql

Table Product
Id name t1 t2
1 A 1 4
2 B 5 2
3 C 3 1
4 D 4 5
Table Tan
id tan
1 tanA
2 tanB
3 tanC
4 tanD
5 tanE
I have two above table and i want the result as below in expecting result how it is possible.
Expecting result
A tanA tanD
B tanE tanB
C tanC tanA
D tanD tanE

You can join on multiple tables:
SELECT p.Name AS ProductName,
t1.tan AS Tan1,
t2.tan AS Tan2
FROM dbo.Product p
INNER JOIN Tan t1
ON p.t1 = t1.id
INNER JOIN Tan t2
ON p.t2 = t2.id
ORDER BY ProductName ASC
Demo

You can select from the tan table twice by using a table alias:
FROM Product INNER JOIN tan tan1 ON tan1.id = product.t1
INNER JOIN tan tan2 ON tan2.id = product.t2
select the appropriate columns:
SELECT Product.name AS name, tan1.tan AS Tan_1, tan2.tan AS Tan_2
to give:
SELECT product.name AS name, tan1.tan AS Tan_1, tan2.tan AS Tan_2
FROM Product INNER JOIN tan tan1 ON tan1.id = product.t1
INNER JOIN tan tan2 ON tan2.id = product.t2

Related

SQL query doesnt return expected values

I have 3 tables. 1st table stores coil information, 2nd table store coil information in transport and 3rd stores reserved coils.
coils
ID
SERIAL
COLOR
MATERIAL
STATUS
1
12345
5
1
2
2
12346
4
1
3
3
12347
3
1
2
coils_in_transport
ID
SERIAL
COLOR
MATERIAL
STATUS
1
f34S5
5
1
2
2
A23GG6
4
1
3
3
ff2S147
3
1
2
reserved_coils
ID
NUMBER
QUANTITY
START
END
1
12345
25
2022-05-01
2023-05-01
3
12347
252
2022-01-01
2023-05-01
4
A23GG6
33
2022-04-01
2023-05-01
5
ff2S147
35
2022-08-01
2023-05-01
I need to write query that will get all reserved coils (reserved_coils) that has status 2 and for each coil I need to join tables for materials and colors
material
ID
NAME
1
color
ID
NAME
I wrote query but it doesn't show coils in transport that are reserved, here is what I tried
SELECT a.QUANTITY, a.START, a.END, b.name, m.name
FROM reserved_coils a
LEFT JOIN coils b ON a.number = b.serial
LEFT JOIN coils_in_transport c ON a.number = c.serial
LEFT JOIN material m ON b.material = m.id
LEFT JOIN material b ON b.material = b.id
where b.status = 2 and c.status = 2
To get all coils and colis_in_transport you need to use UNION for SELECT statements for both tables, each filtered by status value, which should be equal to 2. Then you need to do a JOIN between reserved_coils and the result of UNION to filter out reserved_coils rows.
Your query would be like this
SELECT
r.quantity,
r.start,
r.[end],
c.serial,
material.name AS material,
color.name AS color
FROM reserved_coils r
JOIN (
SELECT * FROM coils WHERE status = 2
UNION
SELECT * FROM coils_in_transport WHERE status = 2
) c ON r.number = c.serial
LEFT JOIN material ON material.id = c.material
LEFT JOIN color ON color.id = c.color
Demo
If you want left join twice on same table, this might help
SELECT a.QUANTITY, a.START, a.[END], isnull(b.serial,c.serial) serial,isnull(c1.name,c2.name) color, isnull(m.name,n.name) material
FROM reserved_coils a
LEFT JOIN coils b ON a.number = b.serial
LEFT JOIN coils_in_transport c ON a.number = c.serial
LEFT JOIN material m ON b.material = m.id
LEFT JOIN material n ON c.material = n.id
LEFT JOIN color c1 on b.color=c1.id
LEFT JOIN color c2 on c.color=c2.id
where isnull(b.status,c.status) = 2
DB<>Fiddle

Many Columns in One Table JOIN one reference table

image. Very new so, please be kind. Using DBForge Query Builder
I have one table with a number of columns which contain abbreviations.
Another table contains the descriptions for the abbreviations.
Need to write a query to replace all the abbreviations with their descriptions. Tried a number of joins without any success. Any ideas?
T1
ID Date Type Cat Sub Cat
1 01/09/18 E F L
2 05/09/18 Cc F D
3 06/09/18 Cc C Dr
4 08/09/18 Cc C Sh
5 08/09/18 E C Sh
T2
Code Des
E Eft Payment
Cc Credit Card
F Food
C Clothes
B Breakfast
L Lunch
D Dinner
Sh Shirt
Dr Dress
Desired Output
ID Date Type D Cat D Sub Cat D
1 01/09/18 Eft Payment Food Lunch
2 05/09/18 Credit Card Food Dinner
3 06/09/18 Credit Card Clothes Dress
4 08/09/18 Credit Card Clothes Shirt
5 08/09/18 Eft Payment Clothes Shirt
Try below using multiple join by T2 with different alias
select
a.ID, a.date,
b.Des as TypeD,
c.Des as CatD,
d.Des as SubCatD
from T1 a inner join T2 b on a.type=b.code
inner join T2 c on a.Cat=c.code
inner join T2 d in a.SubCat=d.code
I will assume the columns of T1 are (ID, Date, Type, Cat, SubCat)
SELECT T1.ID, T1.Date, T2Type.Des, T2Cat.Des, T2SubCat.Des
FROM T1 INNER JOIN T2 T2Type ON T1.Type = T2Type.Code
INNER JOIN T2 T2Cat ON T1.Cat = T2Cat.Code
INNER JOIN T2 T2SubCat ON T1.SubCat = T2SubCat.Code
You need to use multiple instances of the T2 table:
select t1.id, t1.date, typ.des as type_d,ca.des as cat_d,subca.des as sub_cat_d from T1 t1
inner join T2 typ on t1.type=typ.code
inner join T2 ca on t1.cat = ca.code
inner join T2 subca on t1.subcat = subca.code;
Try this...

Order by and limit on a multiple left join - PostgresSQL and python

I have the following relations:
A Product have multiple Images
A Product can have multiple Categories
A Category can have multiple Products
I want to get:
only the 'short_name' from the first category
only the first image url order_by another parameter
I have the following SQL, in PostgreSql:
SELECT DISTINCT ON(I.product_id) P.id, P.name, P.short_description,
CAT.short_name AS category, I.url
FROM products_product AS P
LEFT JOIN products_product_categories AS RPC ON P.id = RPC.product_id
LEFT JOIN categories_category AS CAT ON RPC.category_id = CAT.id
LEFT JOIN products_productimage AS I ON I.product_id = P.id
WHERE (P.is_active = TRUE)
My issue is that I don't know to limit left join and order by, I try to add LIMIT 1
LEFT JOIN categories_category AS CAT ON RPC.category_id = CAT.id LIMIT 1
but it is not working, I receive a code error 'syntax error at or near "LEFT"'
Category table
id | category_name | category_short_name
1 catA A
2 catB B
3 catC C
Product table
id | product_name | product_desc
1 P1 lorem1
2 P2 lorem2
3 P3 lorem3
ManytoMany: product_category
id product_id category_id
1 1 1
2 2 1
3 1 2
4 3 3
5 3 3
Image table
id url product_id order
1 lo1 1 4
2 lo2 1 0
3 lo3 1 1
4 lo4 2 0
For Product with id1 I expect to get:
name: P1, desc 'lorem1', category short_name : cat A, image url lo2
DISTINCT ON makes no sense without ORDER BY. As you want two different orders (on i.order for images and on cat.id for categories), you must do this in separate subqueries.
select p.id, p.name, p.short_description, c.short_name, i.url
from products_product p
left join
(
select distinct on (pcat.product_id) pcat.product_id, cat.short_name
from products_product_categories pcat
join categories_category cat on cat.id = pcat.category_id
order by pcat.product_id, cat.id
) c on c.product_id = p.id
left join
(
select distinct on (product_id) product_id, url
from products_productimage
order by product_id, order
) i on i.product_id = p.id
where p.is_active
order by p.id;
Two alternatives to write this query are:
subqueries with fetch first row only in the select clause
lateral left joins on subqueries with fetch first row only

Most efficient way to SELECT and JOIN these tables

I have 4 tables:
Table1(Groups):
id_group name_group
1 abc
2 def
3 ghi
Table2(Color):
id_color name_color
1 blue
2 red
3 green
Table3(Variety):
id_variety id_color id_group name_variety
1 1 1 light
2 3 1 dark
3 6 2 dark
Table4(Tone):
id_tone id_color id_group name_tone
1 1 1 ocean
2 5 1 sea
3 9 3 clay
Given an id_group like 1 I want to make a selection resulting something like this:
id_group id_color name_variety name_tone
1 1 light ocean
1 3 dark NULL
1 5 NULL sea
I was able to solve the problem with an union and changing the order of the JOINS but I think that there must be another solution
SELECT
GRO.id_group, COL.id_color, VARI.name_variety, TONE.name_tone
FROM
groups GRO
LEFT OUTER JOIN
variety VARI ON (VARI.id_group = GRO.id_group)
LEFT OUTER JOIN
tone TONE ON (TONE.id_group = GRO.id_group)
AND (TONE.id_color = VARI.id_color)
LEFT OUTER JOIN
color COL ON (COL.id_color = VARI.id_color)
OR (COL.id_color = TONE.id_color)
WHERE
GRO.id_group = 1
UNION
SELECT
GRO.id_group, COL.id_color, VARI.name_variety, TONE.name_tone
FROM
groups GRO
LEFT OUTER JOIN
tone TONE ON (TONE.id_group = GRO.id_group)
LEFT OUTER JOIN
variety VARI ON (VARI.id_group = GRO.id_group)
AND (VARI .id_color = TONE.id_color)
LEFT OUTER JOIN
color COL ON (COL.id_color = VARI.id_color)
OR (COL.id_color = TONE.id_color)
WHERE
GRO.id_group = 1
I think what you want is something more like:
SELECT
id_group,
id_color,
MAX(max_variety),
MAX(max_tone)
FROM
(SELECT
v.id_group,
v.id_color,
MAX(name_variety) AS max_variety,
MAX(name_tone) AS max_tone
FROM
variety V INNER JOIN
color c ON
V.id_color = c.id_color LEFT OUTER JOIN
tone t ON
t.id_group = v.id_group AND
t.id_color = V.id_color
WHERE
v.id_group = 1
GROUP BY
v.id_group,
v.id_color
UNION ALL
SELECT
t.id_group,
t.id_color,
MAX(name_variety) AS max_variety,
MAX(name_tone) AS max_tone
FROM
tone t INNER JOIN
color c ON
t.id_color = c.id_color LEFT OUTER JOIN
variety V ON
v.id_group = t.id_group AND
v.id_color = t.id_color
WHERE
t.id_group = 1
GROUP BY
t.id_group,
t.id_color) u
GROUP BY
id_group,
id_color
instead of using union you could use full join , as full join return all result from first table and also all results from the second tables.
SELECT
GRO.id_group, COL.id_color, VARI.name_variety, Tone.name_tone from Variety VARI
join Color COL on col.id_color=VARI col.id
join Groups GRO on GRO.id_group=VARI.id_group
full join Tone on Tone.id_group=GRO.id_group
where GRO.id_group = 1

SQL Server: Subquery on a join

I have two tables with schema and data as below. Table A has an id and an associated name. Table B associates the id from Table A with a price and otherAttr. For each entry in Table A, there may be multiple entries with different prices in Table B, but otherAttr is the same for each entry.
Given an id for Table A, I would like to select the name, otherAttr, and the minimum price.
The below query returns multiple results, I need to write a query that will return a single result with the minimum price.
SELECT a.name, b.price, b.otherAttr
FROM A a
LEFT Join B b on b.idFromA = 1
WHERE a.id = 1
Table A Table B
id | name idFromA | price | otherAttr
-------- ---------------------------
1 | A 1 | 200 | abc
2 | B 1 | 300 | abc
1 | 400 | abc
2 | 20 | def
2 | 30 | def
2 | 40 | ef
I massively oversimplified my example. In addition to selecting the min price and otherAttr from Table B, I also have to select a bunch of other attributes from joins on other tables. Which is why I was thinking the Group By and Min should be a subquery of the join on Table B, as a way to avoid Grouping By all the attributes I am selecting (because the attributes being selected for vary programmatically).
The Actual query looks more like:
SELECT a.name, b.price, b.otherAttr, c.x, c.y, d.e, d.f, g.h....
FROM A a
LEFT Join B b on b.idFromA = 1
LEFT Join C c on something...
LEFT Join D d on something...
LEFT Join G g on something...
WHERE a.id = 1
To get this, you could use GROUP BY in an INNER query:
SELECT gd.name, gd.price,gd.otherAttr, c.x, c.y, d.e, d.f, g.h....
FROM
(SELECT a.id,a.name, MIN(b.price) as price, b.otherAttr
FROM A a
LEFT Join B b on b.idFromA = 1
WHERE a.id = 1
GROUP BY a.id,a.name,b.otherAttr) gd
LEFT Join B b on b.idFromA = 1
LEFT Join C c on something...
LEFT Join D d on something...
LEFT Join G g on something...
Try:-
SELECT a.name, MIN(b.price) minprice, b.otherAttr
FROM A a
LEFT Join B b ON a.Id = b.idFromA
GROUP BY a.name, b.otherAttr
HAVING a.id = 1
You could just do this instead:
SELECT a.name, MIN(b.price), MIN(b.otherAttr)
FROM TableA a
LEFT JOIN TableB b on b.idFromA = a.id
GROUP BY a.name
HAVING a.id = 1;
You need to inner join on price as well in addition to id on the subquery to intersect the right record(s) with the lowest price(s). Then TOP(1) will return only one of those records. You can avoid using TOP(1) if you can expand the conditions and group by fields in the subquery so you schema can assure only a single record is returned for that combination of attributes. Lastly, avoid left joins when intersecting sets.
SELECT TOP(1) p.id, p.price, b.OtherAttr
FROM B as b
INNER JOIN
(SELECT A.id, min(B.price) as price
FROM B
INNER JOIN A on A.id=B.idFromA and A.ID=1
GROUP BY A.id) as p on b.idFromA=p.id and b.price=p.price