SELECT product variants SQL - php

This is my query without variant options
SELECT p.*, pd.`name` AS `product_name`
FROM `product` AS `p`
LEFT JOIN `product_description` AS `pd` ON p.`id` = pd.`product_id`
LEFT JOIN `product_to_variant` AS `pv` ON p.`id` = pv.`product_id`
WHERE p.`status` = 0
GROUP BY p.`id`
ORDER BY p.`id` DESC;
SQLFiddle: http://sqlfiddle.com/#!9/8955b/5
and the follwing query has variant options but it doesn't work
SELECT p.*, pd.`name` AS `product_name`
FROM `product` AS `p`
LEFT JOIN `product_description` AS `pd` ON p.`id` = pd.`product_id`
LEFT JOIN `product_to_variant` AS `pv` ON p.`id` = pv.`product_id`
WHERE p.`status` = 0
AND (pv.`feature_id` = 2 AND pv.`variant_id` = 6)
AND (pv.`feature_id` = 3 AND pv.`variant_id` = 11)
GROUP BY p.`id`
ORDER BY p.`id` DESC;
and I also trying to query but there is no output
SELECT pv.* FROM `product_to_variant` AS `pv`
WHERE (pv.`feature_id` = 2 AND pv.`variant_id` = 2)
AND (pv.`feature_id` = 3 AND pv.`variant_id` = 11)
Do you have any other idea how to receive the products: 14, 15 by specific variant_id 6 AND 11 http://prntscr.com/ect2oh

Here is one method to do what you want:
SELECT p.*, pd.name AS product_name
FROM product p LEFT JOIN
product_description pd
ON p.id = pd.product_id JOIN
product_to_variant pv
ON p.id = pv.product_id
WHERE p.status = 0 AND
((pv.feature_id = 2 AND pv.variant_id = 6) OR
(pv.feature_id = 3 AND pv.variant_id = 11)
)
GROUP BY p.id
HAVING COUNT(DISTINCT feature_id) = 2
ORDER BY p.id DESC;
Notes:
No row can meet your original conditions. Because a column cannot have two values at the same time. Hence the OR rather than AND.
The HAVING clause checks that both values match.
There is no need for a LEFT JOIN to pv, because you are checking values from that table in the WHERE clause -- there have to be matches.
The LEFT JOIN to pa is probably also unnecessary.
Using backticks everywhere just makes the query harder to write and to read.

Maybe like this:
SELECT pv.* FROM `product_to_variant` AS `pv`
WHERE (pv.`feature_id` = 2 AND pv.`variant_id` = 2)
OR (pv.`feature_id` = 3 AND pv.`variant_id` = 11)
Instead of AND, which says, you need both feature_id and variant_id in the results, use OR because it takes both.

Related

UNION ALL use with INNER JOIN

I am trying to join 3 tables with UNION ALL. I tried the following code. and giving this error of Invalid parameter number: number of bound variables does not match number of tokens.
$codeArray = explode(',', $code);
$inQuery = implode(',', array_fill(0, count($codeArray), '?'));
$full_dt = date('Y-m-d H:i:s');
$query = "SELECT * FROM
(
SELECT
a.*
FROM pat_info a
INNER JOIN
pat_medication b
ON a.id = b.pat_id
WHERE
a.status != 2 AND b.status != 2
AND '$full_dt' BETWEEN b.start_date AND b.end_date
AND a.location_code IN ($inQuery)
AND b.stock_status != '2'
AND (b.total_qty - (b.given + b.not_taken)) < 12
UNION ALL
SELECT
a.*
FROM pat_info a
INNER JOIN
prn_medication b
ON a.id = b.pat_id
WHERE
a.status != 2 AND b.status != 2
AND '$full_dt' BETWEEN b.start_date AND b.end_date
AND a.location_code IN ($inQuery)
AND b.stock_status != '2'
AND (b.total_qty - (b.given + b.not_taken)) < 12
) x
GROUP BY a.id ORDER BY a.id DESC";
$statement = $con->prepare($query);
$statement->execute($codeArray);
As you have the in clause twice in your code, you need to bind the values twice.
A simple way to do this would be to duplicate the data prior to the execute()...
$codeArray = array_merge($codeArray, $codeArray);
You also need to change
GROUP BY a.id ORDER BY a.id DESC
to
GROUP BY x.id ORDER BY x.id DESC
as the a alias is in the sub-select and not the overall SELECT.

my query returns duplicates

Hello i have a query that selects products from a database, but for some reason it returns duplicates. The problem is in my joins i guess since in the product table there is no duplicate product. Here is my query:
$stmt=$dbh->prepare("SELECT
p.name,
p.slug,
p.id_product,
p.price,
pig.image,
c1.slug as ssubcat,
c2.slug as subcat,
c3.slug as cat
FROM
tbl_products p
INNER JOIN tbl_products_to_categories ptoc
ON ptoc.id_product = p.id_product
INNER JOIN tbl_catalog_categories c1
ON ptoc.id_category = c1.id_category
LEFT JOIN tbl_catalog_categories c2
ON c1.id_parent = c2.id_category
LEFT JOIN tbl_catalog_categories c3
ON c2.id_parent = c3.id_category
INNER JOIN tbl_products_images_gallery pig
ON pig.id_product = p.id_product
WHERE (c1.slug = :slug OR c2.slug = :slug OR c3.slug = :slug )
AND p.active = 1
AND p.quantity = 1
ORDER BY p.name ASC
LIMIT $start, $row_limit");

simplify this SQL request

I have this sql request :
SELECT pl.*, l.loyer, l.charges, l.locataire_id, laire.nom, laire.prenom,
l.chambre_id, c.numero, c.etage, c.maison_id, m.titre_crm
FROM
(
SELECT spl.id, spl.location_id, spl.mois, spl.annee, spl.loyer_paye
from locations sl
LEFT JOIN
(
SELECT * FROM paiement_loyer
union
SELECT 9999, usl.id, (MONTH(NOW())-1), YEAR(NOW()), 0
FROM locations usl
WHERE usl.id not in (SELECT location_id FROM paiement_loyer) ||
(select count(*) FROM paiement_loyer
WHERE location_id = usl.id AND annee = YEAR(NOW())
AND mois=(MONTH(NOW())-1) ) = 0
) spl ON sl.id = spl.location_id
where sl.date_debut <= CURDATE() && CURDATE() <= sl.date_fin
) pl
JOIN locations l ON pl.location_id = l.id
JOIN locataires laire ON l.locataire_id = laire.id
JOIN chambres c ON l.chambre_id = c.id
JOIN maisons m ON c.maison_id = m.id
ORDER BY trim(upper(m.titre_crm)), c.numero, annee, mois
I would like to simplify it, do you have any idea please ?
An attempt at cleaning it up. Note that I think the first LEFT OUTER JOIN could probably be swapped to an INNER JOIN.
I have swapped the 2nd UNIONed query to 2 queries, and for those I have changed them to use LEFT OUTER JOINs which then check that there isn't a match
SELECT pl.id, pl.location_id, pl.mois, pl.annee, pl.loyer_paye,
l.loyer, l.charges, l.locataire_id, laire.nom, laire.prenom,
l.chambre_id, c.numero, c.etage, c.maison_id, m.titre_crm
FROM
(
SELECT spl.id, spl.location_id, spl.mois, spl.annee, spl.loyer_paye
FROM locations sl
LEFT OUTER JOIN
(
SELECT id, location_id, mois, annee, loyer_paye
FROM paiement_loyer
UNION
SELECT 9999, usl.id, (MONTH(NOW())-1), YEAR(NOW()), 0
FROM locations usl
LEFT OUTER JOIN paiement_loyer pl1
ON usl.id = pl1.location_id
WHERE pl1.location_id IS NULL
SELECT 9999, usl.id, (MONTH(NOW())-1), YEAR(NOW()), 0
FROM locations usl
LEFT OUTER JOIN paiement_loyer pl2
ON usl.id = pl1.location_id
AND pl2.annee = YEAR(NOW())
AND pl2.mois=(MONTH(NOW())-1)
WHERE pl2.location_id IS NULL
) spl ON sl.id = spl.location_id
WHERE CURDATE() BETWEEN sl.date_debut AND sl.date_fin
) pl
JOIN locations l ON pl.location_id = l.id
JOIN locataires laire ON l.locataire_id = laire.id
JOIN chambres c ON l.chambre_id = c.id
JOIN maisons m ON c.maison_id = m.id
ORDER BY TRIM(UPPER(m.titre_crm)), c.numero, pl.annee, pl.mois

How To Left Join A Table Based On The Value Received From Inner Join Of The Same Query

I am trying to run the following query, and I keep getting a syntax error. The query works fine without the LEFT JOIN. How can I implement the LEFT JOIN without error?
SELECT
m.mid,
m.seq,
m.created_on,
m.created_by,
m.body,
r.status,
u.username_clean
FROM message_recipient r
INNER JOIN message m
ON m.mid = r.mid AND m.seq = r.seq
WHERE r.uid = ".$logged_in_id."
AND r.status in ('A', 'N')
AND r.seq = (
SELECT
MAX(rr.seq)
FROM message_recipient rr
WHERE rr.mid = m.mid
AND rr.status in ('A', 'N')
)
AND IF (m.seq=1 and m.created_by = ".$logged_in_id." , 1=0, 1=1)
ORDER BY created_on DESC
LEFT JOIN users u
ON u.user_id = m.created_by
The LEFT JOIN is in the wrong place. All of the JOINs need to be before the WHERE clause:
SELECT
m.mid,
m.seq,
m.created_on,
m.created_by,
m.body,
r.status,
u.username_clean
FROM message_recipient r
INNER JOIN message m
ON m.mid = r.mid AND m.seq = r.seq
LEFT JOIN users u
ON u.user_id = m.created_by
WHERE r.uid = ".$logged_in_id."
AND r.status in ('A', 'N')
AND r.seq = (
SELECT
MAX(rr.seq)
FROM message_recipient rr
WHERE rr.mid = m.mid
AND rr.status in ('A', 'N')
)
AND IF (m.seq=1 and m.created_by = ".$logged_in_id." , 1=0, 1=1)
ORDER BY created_on DESC
The SQL clauses go in the following order:
SELECT
FROM
JOIN
WHERE
GROUP BY
ORDER BY
Even if you have multiple joins they will all appear before the WHERE

MySQL Join returning ALL data from left table and whatever is found in right table

Brain bad. Something isn't clicking that I know is probably simple. I'm trying my best to avoid a subquery but it may be unavoidable.
There are 11 records in the left table [cards_types] and between 1 and 11 records in the right table [users_cards]. I need to return all records from the left table and whatever is found in the right table. The only caveat to the right table is doing some IF / ELSE statements to return 0 values if it card_types.id is not found in users_cards. Also, there is a foreign key constraint on cards_types.id => users_cards.type_id (if it matters).
Query
SELECT
t.id,
t.slug,
t.label AS type_label,
t.points AS point_value,
IF (c.mtg_id IS NULL, 0, c.mtg_id) AS mtg_id,
IF (c.label IS NULL, 0, c.label ) AS card_label,
IF (uc.points IS NULL, 0, uc.points ) AS card_score
FROM cards_types t
JOIN users_cards uc
ON uc.type_id = t.id
JOIN cards c
ON c.id = uc.card_id
WHERE uc.user_id = 1
AND uc.season_id = 1
ORDER BY t.priority ASC
You are currently using an INNER JOIN, change it to a LEFT JOIN. I also moved your WHERE clause filters to the JOIN so you will return all rows from cards_type. If you leave the filters in the WHERE clause, then it will act like an INNER JOIN:
SELECT
t.id,
t.slug,
t.label AS type_label,
t.points AS point_value,
COALESCE(c.mtg_id, 0) AS mtg_id,
COALESCE(c.label, 0) AS card_label,
COALESCE(uc.points, 0) AS card_score
FROM cards_types t
LEFT JOIN users_cards uc
ON uc.type_id = t.id
AND uc.user_id = 1 -- < -- move the where filters here
AND uc.season_id = 1
LEFT JOIN cards c
ON c.id = uc.card_id
ORDER BY t.priority ASC
try with left join like that
SELECT
t.id,
t.slug,
t.label AS type_label,
t.points AS point_value,
COALESCE(c.mtg_id, 0) AS mtg_id,
COALESCE(c.label, 0) AS card_label,
COALESCE(uc.points, 0) AS card_score
FROM cards_types t
LEFT JOIN users_cards uc
ON uc.type_id = t.id
AND uc.user_id = 1
AND uc.season_id = 1
LEFT JOIN cards c
ON c.id = uc.card_id
ORDER BY t.priority ASC

Categories