Joining to table with multiple FKs and Rows - mysql

I have the following query:
SELECT p.id,
p.firstname,
**p.address1id,
p.address2id,**
r.invoice_id,
i.authcode
FROM membershiprenewals r,
Profile p,
Invoice i
WHERE r.orgID = 1
and r.period_id = 3
and r.status = 0
and r.profile_id = p.id
and r.invoice_id = i.id;
This table selects a Users Profile and a few related details.
A Profiles Addresses are stored in another table (profileaddress). And a Profile can have 2 addresses. These addresses are referenced using p.address1 and p.address2.
I need to extend this query to join on the profileaddress table to get BOTH addresses and combined into the single record.
So the results I would need would be the following columns
p.id | p.firstname | .. etc .. | profileaddress1.address | profileaddress1.town | profileaddress2.address | profileaddress2.town | .. etc
I've been playing around with JOIN statements for hours, but just can't seem to crack it.
Any help hugely Appreciated !!
Jason

First, never use commas in the FROM clause. Always use proper, explicit JOIN syntax. So, your query should be:
SELECT p.id, p.firstname, **p.address1id, p.address2id,**
r.invoice_id, i.authcode
FROM membershiprenewals r JOIN
Profile p
ON r.profile_id = p.id JOIN
Invoice i
ON r.invoice_id = i.id
WHERE r.orgID = 1 AND r.period_id = 3 AND r.status = 0;
Then you want two joins to the address table:
SELECT p.id, p.firstname, p.address1id, p.address2id,
pa1.address, pa1.town,
pa2.address, pa2.town,
r.invoice_id, i.authcode
FROM membershiprenewals r JOIN
Profile p
ON r.profile_id = p.id JOIN
Invoice i
ON r.invoice_id = i.id LEFT JOIN
profileaddress pa1
ON p.address1id = pa1.id LEFT JOIN
profileaddress pa2
ON p.address2id = pa2.id
WHERE r.orgID = 1 AND r.period_id = 3 AND r.status = 0;
This uses LEFT JOIN in case one of the addresses is missing.

Related

Get a specific combination from product with given attributes in Prestashop

I building a custom SQL query for my module to retrieve all combinations of a product with id_product and multiple attributes ids, but currently, I only managed to select it with one attribute and no more, I'm really missing something but didn't find it yet.
To get in context here's my query to find all combinations (color & size) of a product and its result:
SELECT
p.id_product,
pq.quantity,
pa.price AS price_diff,
p.price,
pai.id_image,
pl.name,
GROUP_CONCAT(agl.id_attribute_group, ':', pal.id_attribute ORDER BY agl.id_attribute_group SEPARATOR ", ") as combination_ids,
GROUP_CONCAT(pal.name ORDER BY agl.id_attribute_group SEPARATOR ", ") as combination
FROM ps_product p
LEFT JOIN ps_product_attribute pa ON (p.id_product = pa.id_product)
LEFT JOIN ps_stock_available pq ON (p.id_product = pq.id_product AND pa.id_product_attribute = pq.id_product_attribute)
LEFT JOIN ps_product_lang pl ON (p.id_product = pl.id_product)
LEFT JOIN ps_product_attribute_combination pac ON (pa.id_product_attribute = pac.id_product_attribute)
LEFT JOIN ps_attribute_lang pal ON (pac.id_attribute = pal.id_attribute)
LEFT JOIN ps_attribute a ON (pal.id_attribute = a.id_attribute)
LEFT JOIN ps_attribute_group_lang agl ON (a.id_attribute_group = agl.id_attribute_group)
LEFT JOIN ps_product_attribute_image pai on(pa.id_product_attribute = pai.id_product_attribute)
WHERE pl.id_lang = 1
AND pal.id_lang = 1
AND agl.id_lang = 1
AND p.id_product = 3196 -- My product
GROUP BY pac.id_product_attribute
The result
Query with a single attribute (size S for this example):
......................
......................
AND p.id_product = 3196 -- My product
AND agl.id_attribute_group = 9 -- size
AND pal.id_attribute = 761 -- 'S' size for my case
GROUP BY pac.id_product_attribute
But no success with specifying both size AND color, any idea?
I think you want a HAVING clause. To filter on two attributes, the logic would be:
SELECT ...
FROM ...
WHERE ...
GROUP BY pac.id_product_attribute
HAVING
MAX(agl.id_attribute_group = 9 AND pal.id_attribute = 761) = 1
AND MAX(agl.id_attribute_group = 2 AND pal.id_attribute = 727) = 1
I should warn that your code is not a valid aggregation query. You need more column in the GROUP BY clause to fix that flaw. It is hard to tell for sure without seeing your data, but, with a few assumptions on the primary key of each table:
GROUP BY
p.id_product,
pa.id_product_attribute,
pac.id_product_attribute,
pai.id_image,
pq.id -- if that exists?

SQL query left join where clause

This is my situation.
I have 3 tables
Orders
- id status deleted
Order Lines
- related_id related_model quantity
Products
- id code price price_purchase
I want to create a list with all products. The amount of times they are purchased and a sum of the gross margin (price - price_purchase). It must only use orders lines with the related model set to 'products'. And secondly it must only pick orders with the status set to 'paid, processing, sent, ready_for_pickup or picked_up' and with the order not deleted.
So this would be the result I want:
id | code | purchases | value
-------------------------------
1 | code1 | 7 | 57,05
2 | code2 | 122 | 254,98
3 | code3 | 0 | 0,00
This is the SQL query I have so far:
SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
LEFT JOIN shop_orders_lines sol ON sol.related_id = p.id
AND sol.related_model = 'products'
LEFT JOIN shop_orders so ON so.id = sol.order_id
WHERE so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
GROUP BY p.id
It returns the correct data. But not all problems. That is my problem. I a lot of different methods like sub queries and other methods but can't seem to solve the problem. I know the problem is my LEFT join, but don't know a solution to my problem.
I'm using MySQL Workbench.
Any help is welcome.
Your joins are wrong. You need to identify the order lines to consider separately from and prior to forming the LEFT JOIN with the product details. An inline view could help:
SELECT
p.id,
p.code,
IFNULL(SUM(ordered_item.quantity) , 0) as purchases ,
sum((p.price - p.price_purchase) * ordered_item.quantity) as value
FROM
products p
LEFT JOIN (
SELECT
sol.related_id AS related_id,
sol.quantity AS quantity
FROM
shop_orders_lines sol
INNER JOIN shop_orders so
ON so.id = sol.order_id
WHERE
so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
AND sol.related_model = 'products'
) ordered_item
ON ordered_item.related_id = p.id
GROUP BY p.id
Move outer table conditions from WHERE to ON, otherwise the OUTER JOIN works like a regular INNER JOIN:
SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
LEFT JOIN shop_orders_lines sol ON sol.related_id = p.id
AND sol.related_model = 'products'
LEFT JOIN shop_orders so ON so.id = sol.order_id AND
so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
GROUP BY p.id
Is p.id the whole primary key for that table? If not, you need to find out how to treat p.code. (Either list in GROUP BY, or use as argument to aggregate function.)
Another try:
SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
JOIN shop_orders_lines sol ON sol.related_id = p.id
AND sol.related_model = 'products'
WHERE EXISTS (select 1 from shop_orders so
where so.id = sol.order_id
AND so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0)
GROUP BY p.id

Selecting from different tables based on condition

I Have a table comments ->
id | comment | type | userid |
1 Hello human 9
2 Hi robot 4
3 Gnaw! animal 1
4 Boo ghost 2
Also i have four more tables human,robot,ghost and animal
These tables contains some basic details about themselves...
Now I have a know value of comment say : $id = 3
if i do
$data = mysqli_query($con,"SELECT type FROM comments WHERE id = $id");
while($row = mysqli_fetch_assoc($data)){
$table = $row['type'];
$table_data = mysqli_fetch_assoc(mysqli_query($con,"SELECT * FROM $table"));
}
this will fetch me all the data about the one who commented but this will prove to be too slow....is there any way i can combine this in one single query ?
One way to do this is with left joins.
SELECT c.type, COALESCE(h.detail,r.detail,a.detail,g.detail)
FROM comments
LEFT JOIN human h ON c.type = 'human' AND c.id = h.id
LEFT JOIN robot r ON c.type = 'robot' AND c.id = r.id
LEFT JOIN animal a ON c.type = 'animal' AND c.id = a.id
LEFT JOIN ghost g ON c.type = 'ghost' AND c.id = g.id
Another way would be to do a UNION on the four tables and then join those:
SELECT c.type, q1.detail
FROM comments c
LEFT JOIN
(
SELECT 'human' AS type, detail FROM human
UNION
SELECT 'robot', detail FROM robot
(etc.)
) q1 ON c.type = q1.type AND q1.id = c.id
I would prefer the second option, because this one makes it easier to join lots of detail-columns. I don't think there's much of a difference perfomance-wise.

SQL JOIN Query - linking four tables

I have the SQL to display ALL the activities and relative Admin permissions (if any) for that activity.
Current SQL Code:
SELECT `activities`.*, `admins`.`admin_role_id`
FROM (`activities`)
LEFT JOIN `admins` ON `admins`.`activity_id`=`activities`.`id` AND admins.member_id=27500
WHERE `activities`.`active` = 1
Returning:
id | name | description | active | admin_role_id (or null)
I then need to detect whether they are an active member within that Activity.
I have the following SQL code:
SELECT DISTINCT `products`.`activity_ID` as joinedID
FROM (`transactions_items`)
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`
JOIN `activities` ON `activities`.`id` = `products`.`activity_ID`
WHERE `transactions`.`member_id` = 27500
AND `activities`.`active` = 1
Is there any way to merge this into one SQL query. I can't figure out how to use the correct JOIN queries, because of the complexity of the JOINs.
Help please, thanks! :)
Try like this
SELECT `activities`.*, `admins`.`admin_role_id`
FROM (`activities`)
LEFT JOIN `admins` ON `admins`.`activity_id`=`activities`.`id` AND admins.member_id=27500
JOIN (`transactions_items`
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`)
ON `activities`.`id`=`products`.`activity_ID`
WHERE `transactions`.`member_id` = 27500
AND `activities`.`active` = 1
Seems to me that a query like this would be marginally more comprehensible and (I think) adhere more closely to the spec...
SELECT c.*
, d.admin_role_id
FROM activities c
LEFT
JOIN admins d
ON d.activity_id = c.id
AND d.member_id = 27500
LEFT
JOIN products p
ON p.activity_ID = c.id
LEFT
JOIN transactions_items ti
ON ti.product_id = p.id
LEFT
JOIN transactions t
ON t.id = ti.id
AND t.member_id = 27500
WHERE c.active = 1

MySQL / PHP - 2 different arguments for 1 table

I have the following SQL:
$queryString = "
SELECT
iR.lastModified,
d.*,
c2.title as stakeholderTitle,
u.username as authorUsername,
c.title as authorContactName,
GROUP_CONCAT(iR.stakeholderRef) AS participants
FROM
informationRelationships iR,
contacts c2
INNER JOIN
debriefs d ON
d.id = iR.linkId
LEFT JOIN
users u ON
u.id = iR.author
LEFT JOIN
contacts c ON
c.ref = u.contactId
LEFT JOIN
debriefs d2 ON
d2.stakeholder = c2.ref
WHERE
(
iR.clientRef = '$clientRef' OR
iR.contactRef = '$contactRef'
)
AND
iR.projectRef = '$projectRef' AND
iR.type = 'Debrief'
GROUP BY
iR.linkId
ORDER BY
d.dateOfEngagement
";
notice how I require 2 different bits of data for the the contacts table.
So at one point, I need to match
c.ref = u.contactId
This will return one bit of information
but I also need a completely different grouping:
d2.stakeholder = c2.ref
Problem is that the title is the column i'm interested in for both:
c2.title as stakeholderTitle,
...
c.title as authorContactName
How do I go about doing this?
My current try is returning:
Error: Unknown column 'iR.linkId' in 'on clause'
I'm not sure I really understand what is happening here:
how to join two tables on common attributes in mysql and php?
EDIT::::---ANSWERED--zerkms
$queryString = "
SELECT
iR.lastModified,
d.*,
c2.title as stakeholderTitle,
u.username as authorUsername,
c.title as authorContactName,
GROUP_CONCAT(iR.stakeholderRef) AS participants
FROM
informationRelationships iR
INNER JOIN
debriefs d ON
d.id = iR.linkId
INNER JOIN
contacts c2 ON
d.stakeholder = c2.ref
LEFT JOIN
users u ON
u.id = iR.author
LEFT JOIN
contacts c ON
c.ref = u.contactId
WHERE
(
iR.clientRef = '$clientRef' OR
iR.contactRef = '$contactRef'
)
AND
iR.projectRef = '$projectRef' AND
iR.type = 'Debrief'
GROUP BY
iR.linkId
ORDER BY
d.dateOfEngagement
";
By re-ordering my query I have managed to get both columns in... Thanks zerkms!
You cannot mix implicit joins and explicit joins in a single query in mysql.
So
FROM informationRelationships iR,
contacts c2
should be rewritten to
FROM informationRelationships iR
INNER JOIN contacts c2 ON ...
Do not use cartesian product and joins in the same query (not subquery), here, use only joins (CROSS JOIN is the same as cartesian product).