The following query fails in MySQL 5.1.56:
SELECT
shop_id, products.product_id AS
product_id, brand, title, price, image, image_width, image_height
FROM products, users LEFT JOIN
(
SELECT fav5.product_id AS product_id, SUM(CASE
WHEN fav5.current = 1 AND fav5.closeted = 1 THEN 1
WHEN fav5.current = 1 AND fav5.closeted = 0 THEN -1
ELSE 0
END) AS favorites_count
FROM favorites fav5
GROUP BY fav5.product_id
) AS fav6 ON products.product_id=fav6.product_id
WHERE products.product_id= 46876 AND users.user_id!=products.product_id
The error is
#1054 - Unknown column 'products.product_id' in 'on clause'
This modification without the user table does not fail:
SELECT
shop_id, products.product_id AS
product_id, brand, title, price, image, image_width, image_height
FROM products LEFT JOIN
(
SELECT fav5.product_id AS product_id, SUM(CASE
WHEN fav5.current = 1 AND fav5.closeted = 1 THEN 1
WHEN fav5.current = 1 AND fav5.closeted = 0 THEN -1
ELSE 0
END) AS favorites_count
FROM favorites fav5
GROUP BY fav5.product_id
) AS fav6 ON products.product_id=fav6.product_id
WHERE products.product_id= 46876
Neither query fails in MySQL 5.0.67. (I exported the database from 5.0.67 and imported into 5.1.56 so the structure should be identical.)
The products table does have a product_id column, of type int(10). The favorites table also has a product_id column of type int(10). What is going on?
As easy as swap from tables order:
FROM users, products LEFT JOIN
Be careful, you are mixing join notations.
JOIN processing operator precedence has changed in MySQL in 5.1. It's a common problem for people upgrading from 5.0
MySQL LEFT JOIN after 5.0.12 changes - How to rewrite query
This is your original query, reformatted a little and with two parentheses added:
SELECT shop_id, products.product_id AS
product_id, brand, title, price, image, image_width, image_height
FROM products,
( -- Parenthesis added
users LEFT JOIN
(
SELECT fav5.product_id AS product_id, SUM(CASE
WHEN fav5.current = 1 AND fav5.closeted = 1 THEN 1
WHEN fav5.current = 1 AND fav5.closeted = 0 THEN -1
ELSE 0
END) AS favorites_count
FROM favorites fav5
GROUP BY fav5.product_id
) AS fav6 ON products.product_id=fav6.product_id
) -- Parenthesis added
WHERE products.product_id= 46876 AND users.user_id!=products.product_id
The parentheses indicate how the SQL parser is interpreting the query, and there is no products table within the added parenthesis.
It is a bad idea to mix the old style and new (as in, since SQL-92) style joins.
Use:
SELECT shop_id, products.product_id AS
product_id, brand, title, price, image, image_width, image_height
FROM products JOIN users ON users.user_id != products.product_id
LEFT JOIN
(SELECT fav5.product_id AS product_id,
SUM(CASE WHEN fav5.current = 1 AND fav5.closeted = 1 THEN 1
WHEN fav5.current = 1 AND fav5.closeted = 0 THEN -1
ELSE 0
END) AS favorites_count
FROM favorites fav5
GROUP BY fav5.product_id
) AS fav6 ON products.product_id=fav6.product_id
WHERE products.product_id = 46876
The != join is going to be slow (it practically a Cartesian product).
Related
Sorry for asking here this but I need help and google is not being nice.
I have the following table Products
SELECT
COUNT(CASE when core.kits.Location = core.suppliers.id THEN 1 END) as total,
COUNT(CASE when core.kits.cp = 1 THEN 1 END) as used,
core.suppliers.id, core.suppliers.name, core.suppliers.email,
core.suppliers.cperson, core.suppliers.adress, core.suppliers.phone
FROM core.kits
LEFT join core.suppliers on core.kits.Location = core.suppliers.id
WHERE core.suppliers.id is not null
AND banned=0
GROUP BY core.suppliers.id
ORDER BY name ASC
LIMIT 1000 OFFSET 0
but does not give me all the suppliers with zeros for the ones who have no appearance in kits.
Then in I do
SELECT
COUNT(CASE when core.kits.Location = core.suppliers.id THEN 1 END) as total,
COUNT(CASE when core.kits.cp = 1 THEN 1 END) as used,
core.suppliers.id, core.suppliers.name, core.suppliers.email,
core.suppliers.cperson, core.suppliers.adress, core.suppliers.phone
FROM core.suppliers
LEFT join core.suppliers on core.suppliers.id = core.kits.Location
WHERE core.suppliers.id is not null
AND banned=0
GROUP BY core.suppliers.id
ORDER BY name ASC
LIMIT 1000 OFFSET 0
I get all suppliers and correct numbers but the query takes 8 seconds instead of 1s. Any ideas how can I get all the suppliers with the count of stocks in 1s?
cheers.
If you want all the suppliers, even those that do not appear in kits you should do a LEFT join of suppliers to kits:
SELECT COUNT(k.Location) AS total,
COUNT(CASE WHEN k.cp = 1 THEN 1 END) AS used,
s.id, s.name, s.email, s.cperson, s.adress, s.phone
FROM core.suppliers s LEFT JOIN core.kits k
ON k.Location = s.id
WHERE banned=0
GROUP BY s.id
ORDER BY s.name ASC
LIMIT 1000 OFFSET 0;
I assume that core.suppliers.id is the primary key of suppliers, so that the conition:
core.suppliers.id is not null
is not needed.
Also, if the column banned is contained in the table kits, then the condition should be moved in the ON clause:
ON k.Location = s.id AND k.banned=0
and the WHERE clause should be removed.
I've been scratching my head on this for days! I made the query below to combine two subqueries and group them by date. The first query in the derived table returns 50 rows, while the second query returns 2 rows.
But if I run the whole thing, it only returns the 50 rows from the FIRST query.
AND whatever should have been combined from the second query IS NOT combined at all to the rows with the same GROUP BY column value.
SELECT tot.payment_date AS "Payment Period",
tot.total_sales AS "Total Sales"
FROM
(
SELECT DATE_FORMAT(a.payment_dt, "%c/%d/%Y") AS payment_date,
CAST((SUM(b.ucost * b.qty) + a.shipping_fee) AS DECIMAL(15,2)) AS total_sales
FROM tbl_encash_order_sum a
INNER JOIN tbl_encash_order_det b
ON a.accid = b.accid AND a.so_no = b.so_no
WHERE a.payment_stat = 1
GROUP BY DATE_FORMAT(a.payment_dt, "%c/%d/%Y")
UNION ALL
SELECT DATE_FORMAT(d.dp_settled_dt, "%c/%d/%Y") AS payment_date,
SUM(d.order_total) AS total_sales
FROM wp_posts c
INNER JOIN
(
SELECT post_id,
MAX(CASE WHEN meta_key = "_payment_status" THEN CAST(meta_value AS SIGNED) END) AS payment_status,
MAX(CASE WHEN meta_key = "_order_total" THEN CAST(meta_value AS DECIMAL(15,2)) END) AS order_total,
MAX(CASE WHEN meta_key = "_dp_settled_dt" THEN CAST(meta_value AS DATETIME) END) AS dp_settled_dt
FROM wp_postmeta
GROUP BY post_id
) d
ON c.ID = d.post_id
WHERE c.post_type = "shop_order" AND d.payment_status = 1
GROUP BY DATE_FORMAT(d.dp_settled_dt, "%c/%d/%Y")
) tot
GROUP BY tot.payment_date
ORDER BY tot.payment_date
Here:
SELECT tot.payment_date AS "Payment Period",
tot.total_sales AS "Total Sales"
you should be doing SUM(tot.total_sales). Without the sum, it will return an arbitrary one of the total sales for each payment date.
You can make mysql give an error instead of choosing arbitrary data to return by enabling the ONLY_FULL_GROUP_BY sqlmode.
I have got the result form a complex query below
SELECT o_items.sku,
o_items.name AS 'title',
o_items.qty_ordered AS 'quantity',
s_orders.base_amount_paid AS 'paid/unpaid'
FROM sales_order_payment s_orders
INNER JOIN (SELECT s.sku, s.name, s.qty_ordered, s.order_id
FROM sales_order_item s
INNER JOIN (SELECT p.entity_id
FROM catalog_product_entity AS p
INNER JOIN catalog_product_entity_int AS a
ON p.row_id = a.row_id
WHERE VALUE >= 0
AND
a.attribute_id =
(SELECT attribute_id
FROM eav_attribute
WHERE attribute_code = 'is_darkhorse')) as q
ON s.product_id = q.entity_id
WHERE s.created_at BETWEEN '2019-01-14' AND '2019-01-16') o_items
ON
s_orders.parent_id = o_items.order_id
this is the order data those have been paid or not paid yet. Amount is representing paid and Null representing unpaid status
I am trying to generate below result but couldn't succeed and need help. Actually this result is showing how may quantity of a product has been paid and how many not paid yet. This would be result of above fetched data.
Please guide me how can i proceed to achieve these result.
Use this. ... represent existing code.
select .... , sum(case when s_orders.base_amount_paid is not null
then o_items.qty_ordered
else 0
end) as paid,
sum(case when s_orders.base_amount_paid is null
then o_items.qty_ordered
else 0
end) as unpaid
From .......
You can use if and ifnull functions together(presuming you're using mysql as DBMS)
and GROUP BY expression
SELECT c.sku, c.name,
sum(if(ifnull(base_amount_paid,0)=0,0,1)) as paid,
sum(if(ifnull(qty_ordered,0)=0,0,1)) as unpaid
FROM catalog_prod_ent_derived c
GROUP BY c.sku, c.name
where catalog_prod_ent_derived represents your whole query as a subquery.
In below query (Mentors) are 13 which shows me 26, while (SchoolSupervisor) are 5 which shows me 10 which is wrong. it is because of the Evidence which having 2 evidance, because of 2 evidence the Mentors & SchoolSupervisor values shows me double.
please help me out.
Query:
select t.c_id,t.province,t.district,t.cohort,t.duration,t.venue,t.v_date,t.review_level, t.activity,
SUM(CASE WHEN pr.p_association = "Mentor" THEN 1 ELSE 0 END) as Mentor,
SUM(CASE WHEN pr.p_association = "School Supervisor" THEN 1 ELSE 0 END) as SchoolSupervisor,
(CASE WHEN count(file_id) > 0 THEN "Yes" ELSE "No" END) as evidence
FROM review_m t , review_attndnce ra
LEFT JOIN participant_registration AS pr ON pr.p_id = ra.p_id
LEFT JOIN review_files AS rf ON rf.training_id = ra.c_id
WHERE 1=1 AND t.c_id = ra.c_id
group by t.c_id, ra.c_id order by t.c_id desc
enter image description here
You may perform the aggregations in a separate subquery, and then join to it:
SELECT
t.c_id,
t.province,
t.district,
t.cohort,
t.duration,
t.venue,
t.v_date,
t.review_level,
t.activity,
pr.Mentor,
pr.SchoolSupervisor,
rf.evidence
FROM review_m t
INNER JOIN review_attndnce ra
ON t.c_id = ra.c_id
LEFT JOIN
(
SELECT
p_id,
COUNT(CASE WHEN p_association = 'Mentor' THEN 1 END) AS Mentor,
COUNT(CASE WHEN p_association = 'School Supervisor' THEN 1 END) AS SchoolSupervisor,
FROM participant_registration
GROUP BY p_id
) pr
ON pr.p_id = ra.p_id
LEFT JOIN
(
SELECT
training_id,
CASE WHEN COUNT(file_id) > 0 THEN 'Yes' ELSE 'No' END AS evidence
FROM review_files
GROUP BY training_id
) rf
ON rf.training_id = ra.c_id
ORDER BY
t.c_id DESC;
Note that this also fixes another problem your query had, which was that you were selecting many columns which did not appear in the GROUP BY clause. Under this refactor, there is nothing wrong with your current select, because the aggregation take place in a separate subquery.
try adding this to the WHERE part of your query
AND pr.p_id IS NOT NULL AND rf.training_id IS NOT NULL
You can add a group by pr.p_id to remove the duplicate records there. Since, the group by on pr is not present as of now, there might be multiple records of same p_id for same ra
group by t.c_id, ra.c_id, pr.p_id order by t.c_id desc
I have a problem with a query:
I have a list of stores, each of these stores has members and there are various categories of membership (Bronze, silver, gold ...)
The tables are: 'shops', 'members', 'membership_cards'.
shops: id, name
members: id, shops_id, membership_id, first_name, last_name
membership_cards: id, description
I need to extract the count of members, grouped by membership of each stores. Can I do this without using a server side language?
The final result should be something like:
Store's name, n°bronze members, n°silver_members, n°gold_members ....
Based on what you provided, you want a query like:
select shopid,
sum(case when c.cardtype = 'Bronze' then 1 else 0 end) as Bronze,
sum(case when c.cardtype = 'Silver' then 1 else 0 end) as Silver,
sum(case when c.cardtype = 'Gold' then 1 else 0 end) as Gold
from shops s left outer join
members m
on s.shopid = m.shopid left outer join
cards c
on c.memberid = m.memberid
group by shopid
If you want to know the number of members, rather than of cards in each group (if members can have more than one card), then replace the sum() expression with:
count(case when c.cardtype = 'Bronze' then m.memberid end)
Without knowing your database schema, it's a bit hard to answer that question, but something like the following should do the job:
SELECT shop.name,
SUM(CASE WHEN membership_cards.category = 'Bronze' THEN 1 ELSE 0 END) AS Bronze,
SUM(CASE WHEN membership_cards.category = 'Silver'THEN 1 ELSE 0 END) AS Silver,
SUM(CASE WHEN membership_cards.category = 'Gold' THEN 1 ELSE 0 END) AS Gold
FROM shops
INNER JOIN members
ON shop.id = members.shopid
INNER JOIN membership_cards
ON members.id = membership_cards.memberid
GROUP BY shop.name
Just change the column names to the names you are using.
SELECT B.name,A.Bronze,A.Silver,A.Gold
FROM
(
SELECT S.id,
SUM(IF(IFNULL(C.cardtype,'')='Bronze',1,0)) Bronze,
SUM(IF(IFNULL(C.cardtype,'')='Silver',1,0)) Silver,
SUM(IF(IFNULL(C.cardtype,'')='Gold' ,1,0)) Gold
FROM shops S
LEFT JOIN members M ON S.id = M.shops_id
LEFT JOIN membership_cards C ON M.membership_id = C.id
GROUP BY S.id
) A
INNER JOIN shops B USING (id);
I used the IFNULL function in case any member has no cards