how to join these tables in sql - sql

I have these tables and would like to query them to show the all clients and their groups (if any), the following image describes the case:
How to join tables to get the result using sql server?

This looks like a lesson teaching CROSS JOIN. Because you want a row in your result for each intersection of client and group, whether or not it is valid, you want to cross join those tables then see if there is a matching record in client_group. In a working application this cross join could get unwieldy very quickly, with a few thousand groups and clients you'd have many millions of results.
Something like this should get your cartesian result and see if a matching record is found:
SELECT
c.id 'client_id', g.Id 'group_id', ISNULL(cg.client_id)
FROM
(client c
CROSS JOIN group g)
LEFT JOIN client_group cg ON c.id = cg.client_id AND g.id = cg.group_id
More on joining:
What is the difference between Left, Right, Outer and Inner Joins?

Related

How to build a complex sql query?

Database design here
I want to get records from the product_spec_data table that are associated with products whose category_id is 5.
Please help me make a query to the database...
All of the relationship are clearly laid out, a simple join across tables would works.
SELECT psd.*
FROM product_spec_data psd
INNER JOIN product_spec_values psv ON psd.id = psv.product_spec_data_id
INNER JOIN products prod ON psv.product_id = prod.id
INNER JOIN categories cat ON prod.category_id = cat.id
-- with category id = 5
WHERE cat.id = 5;
I am not sure what do you mean by complex query. I guess your question is not complete. I think the query for your question (if it is T-SQL) will be as follows
select d.*
from product_spec_data d
left outer join product_spec_values v on d.id=v.product_spec_data_id
left outer join products p on v.product_id=p.id
where p.category_id=5
(I think in MySQL also above syntax will remain same, you may remove [outer] clause in MySQL)

Struggling to interpret this SQL join syntax

Two pretty similar queries:
Query #1:
SELECT *
FROM employee e
LEFT JOIN employee_payments ep
INNER JOIN payments p ON ep.payment_id = p.id
ON ep.employee_id = e.id
Query #2:
SELECT *
FROM employee e
LEFT JOIN employee_payments ep ON ep.employee_id = e.id
INNER JOIN payments p ON ep.payment_id = p.id
But obviously crucially different syntax.
The way I learn these new syntax concepts best are to interpret them as plain English. So how could you describe what these are selecting?
I would expect that they'd produce the same results, but it feels to me like the LEFT JOIN in the second query acts as an INNER JOIN somehow - since a fraction of my results set are returned (i.e. the employees with payments).
If the first query 'says' "give me all employees, along with any available employee_payments (that have already been joined with their payment record)"- what does the second query say?
If the first query 'says' "give me all employees, along with any available employee_payments (that have already been joined with their payment record)"- what does the second query say?
I suppose you might put it as "Take all employees along with any available employee_payments. Join this with the payment records."
The "Join this with the payment records" is what filters out employees that don't have any associated employee_payments records: the attempt to join with the payment records will fail.
but it feels to me like the LEFT JOIN in the second query acts as an INNER JOIN somehow
It's not the LEFT JOIN that's doing the filtering, but it does indeed give the exact same result as if the LEFT JOIN had been an INNER JOIN.
In order to understand the logical order1 in which joins happen, you need to look at the ON clauses. For each ON clause that you encounter, you pair it with the closest previous JOIN clause that hasn't already been processed. This means that you first query is:
INNER JOIN ep to p (producing, say, ep')
LEFT JOIN e to ep'
And your second query is:
LEFT JOIN e to ep (producing, say, e')
INNER JOIN e' to p
Since the conditions of the INNER JOIN rely upon columns present in ep, this is why the different join orders matter here.
1The logical join order determines the final shape of the result set. SQL Server is free to perform joins in any order it sees fit, but it must produce results consistent with the logical join order.

sql multiple outer joins on multiple fields

SQL beginner here.
I am trying to outer-join one table (pgm_update) to two other tables (family and family_act_visits). A pgm_update record may correspond to a family record or a family_act_visits record or neither; my results should return data for all three cases. Both of some bad architecture, the joins have to be on multiple columns. Each of these individual queries works, but I haven't been able to combine them into a single query.
SELECT p.last_name_wo, p.activity, p.participation, fav.*
FROM family_act_visits fav
RIGHT JOIN pgm_update p ON fav.folks_fk=p.folks_fk and fav.activity=p.activity
JOIN activities a on p.activity=a.activity
WHERE p.participation in ('c','a') and a.act_start_date>current_date()
SELECT p.last_name_wo, p.activity, p.participation, f.*
FROM family f
RIGHT JOIN pgm_update p ON f.folks_fk=p.folks_fk and f.activity=p.activity
JOIN activities a on p.activity=a.activity
WHERE p.participation in ('c','a') and a.act_start_date>current_date()
One of my attempts at the full query is:
SELECT p.last_name_wo, p.activity, p.participation, fav.*
FROM family_act_visits fav, family f
RIGHT JOIN pgm_update p ON fav.folks_fk=p.folks_fk and fav.activity=p.activity
RIGHT JOIN pgm_update p2 ON f.folks_fk=p2.folks_fk and f.activity=p2.activity
JOIN activities a on p.activity=a.activity
WHERE p.participation in ('c','a') and a.act_start_date>current_date()
This gets the error message "Unknown column 'fav.folks_fk' in 'on clause'"
Hope this long post contains all the info needed....thanks!
Firstly, JOINing on multiple conditions does not indicate poor design.
Are you sure you want a RIGHT JOIN?
Perhaps you are looking for LEFT JOIN
Your query is a bit complicated, and it includes a CROSS JOIN, perhaps unintentionally?
Perhaps you just want to UNION ALL which allows you to append datasets having the same shape....
SELECT
p.last_name_wo
,p.activity
,p.participation
,fav.*
FROM
family_act_visits fav
RIGHT JOIN pgm_update p
ON fav.folks_fk=p.folks_fk
AND fav.activity=p.activity
JOIN activities a
ON p.activity=a.activity
WHERE
p.participation IN ('c','a')
AND a.act_start_date>current_date()
UNION ALL
SELECT
p.last_name_wo
,p.activity
,p.participation
,f.*
FROM
family f
RIGHT JOIN pgm_update p
ON f.folks_fk=p.folks_fk
AND f.activity=p.activity
JOIN activities a
ON p.activity=a.activity
WHERE
p.participation IN ('c','a')
AND a.act_start_date>current_date()

When I add a LEFT OUTER JOIN, the query returns only a few rows

The original query returns 160k rows. When I add the LEFT OUTER JOIN:
LEFT OUTER JOIN Table_Z Z WITH (NOLOCK) ON A.Id = Z.Id
the query returns only 150 rows. I'm not sure what I'm doing wrong.
All I need to do is add a column to the query, which will bring back a code from a different table. The code could be a number or a NULL. I still have to display NULL, hence the reason for the LEFT join. They should join on the "id" columns.
SELECT <lots of stuff> + the new column that I need (called "code").
FROM
dbo.Table_A A WITH (NOLOCK)
INNER JOIN
dbo.Table_B B WITH (NOLOCK) ON A.Id = B.Id AND A.version = B.version
--this is where I added the LEFT OUTER JOIN. with it, the query returns 150 rows, without it, 160k rows.
LEFT OUTER JOIN
Table_Z Z WITH (NOLOCK) ON A.Id = Z.Id
LEFT OUTER JOIN
Table_E E WITH (NOLOCK) ON A.agent = E.agent
LEFT OUTER JOIN
Table_D D WITH (NOLOCK) ON E.location = D.location
AND E.type = 'Organization'
AND D.af_type = 'agent_location'
INNER JOIN
(SELECT X , MAX(Version) AS MaxVersion
FROM LocalTable WITH (NOLOCK)
GROUP BY agemt) P ON E.agent = P.location AND E.Version = P.MaxVersion
Does anyone have any idea what could be causing the issue?
When you perform a LEFT OUTER JOIN between tables A and E, you are maintaining your original set of data from A. That is to say, there is no data, or lack of data, in table E that can reduce the number of rows in your query.
However, when you then perform an INNER JOIN between E and P at the bottom, you are indeed opening yourself up to the possibility of reducing the number of rows returned. This will treat your subsequent LEFT OUTER JOINs like INNER JOINs.
Now, without your exact schema and a set of data to test against, this may or may not be the exact issue you are experiencing. Still, as a general rule, always put your INNER JOINs before your OUTER JOINs. It can make writing queries like this much, much easier. Your most restrictive joins come first, and then you won't have to worry about breaking any of your outer joins later on.
As a quick fix, try changing your last join to P to a LEFT OUTER JOIN, just to see if the Z join works.
You have to be very careful once you start with LEFT JOINs.
Let's suppose this model: You have tables Products, Orders and Customers. Not all products necessarily have been ordered, but every order must have customer entered.
Task: Show all products, and if the product was ordered, list the ordering customers; i.e., product without orders will be shown as one row, product with 10 orders will have 10 rows in the resultset. This calls for a query designed around FROM Products LEFT JOIN Orders.
Now someone could think "OK, Customer is always entered into orders, so I can make inner join from orders to customers". Wrong. Since the table Customers is joined through left-joined table Orders, it has to be left-joined itself... otherwise the inner join will propagate into the previous level(s) and as a result, you will lose all products that have no orders.
That is, once you join any table using LEFT JOIN, any subsequent tables that are joined through this table, need to keep LEFT JOINs. But it does not mean that once you use LEFT JOIN, all joins have to be of that type... only those that are dependent on the first performed LEFT JOIN. It would be perfectly fine to INNER JOIN the table Products with another table Category for example, if you only want to see Products which have a category set.
(Answer is based on this answer: http://www.sqlservercentral.com/Forums/Topic247971-8-1.aspx -> last entry)

Mysql statement (syntax error on FULL JOIN)

What is wrong with my sql statement, it says that the problem is near the FULL JOIN, but I'm stumped:
SELECT `o`.`name` AS `offername`, `m`.`name` AS `merchantName`
FROM `offer` AS `o`
FULL JOIN `offerorder` AS `of` ON of.offerId = o.id
INNER JOIN `merchant` AS `m` ON o.merchantId = m.id
GROUP BY `of`.`merchantId`
Please be gentle, as I am not a sql fundi
MySQL doesn't offer full join, you can either use
a pair of LEFT+RIGHT and UNION; or
use a triplet of LEFT, RIGHT and INNER and UNION ALL
The query is also very wrong, because you have a GROUP BY but your SELECT columns are not aggregates.
After you convert this properly to LEFT + RIGHT + UNION, you still have the issue of getting an offername and merchantname from any random record per each distinct of.merchantid, and not even necessarily from the same record.
Because you have an INNER JOIN condition against o.merchant, the FULL JOIN is not necessary since "offerorder" records with no match in "offer" will fail the INNER JOIN. That turns it into a LEFT JOIN (optional). Because you are grouping on of.merchantid, any missing offerorder records will be grouped together under "NULL" as merchantid.
This is a query that will work, for each merchantid, it will show just one offer that the merchant made (the one with the first name when sorted in lexicographical order).
SELECT MIN(o.name) AS offername, m.name AS merchantName
FROM offer AS o
LEFT JOIN offerorder AS `of` ON `of`.offerId = o.id
INNER JOIN merchant AS m ON o.merchantId = m.id
GROUP BY `of`.merchantId, m.name
Note: The join o.merchantid = m.id is highly suspect. Did you mean of.merchantid = m.id? If that is the case, change the LEFT to RIGHT join.