Optimize a MySQL query with UNIONs - mysql

I need to run a long MySQL query which contains several UNIONs. Some subqueries are taking much time resulting a long run time. I have made indexes on tables but still it takes around 15 seconds to run. I need to reduce the run time to 1 second.
Here is the query:
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, NULL AS Ink_Type, NULL AS Industry,
NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, pi.prd_img_name
FROM products p
LEFT JOIN product_image_p pi ON p.prd_id = pi.prd_id
WHERE p.is_deleted = 'no'
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, GROUP_CONCAT(decoration.dm_name SEPARATOR ', ') AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material,
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_dm pdm ON pdm.prd_id = p.prd_id
JOIN decoration_method decoration ON decoration.dm_id = pdm.dm_id
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, GROUP_CONCAT(rush.rush_title SEPARATOR ', ') AS Rush_Production, NULL AS Themes, NULL AS Material,
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_rush_title prt ON prt.prd_id = p.prd_id
JOIN rush_title rush ON rush.rush_id = prt.rush_id
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, GROUP_CONCAT(ao.option_name SEPARATOR ', ') AS Item_Color,
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, NULL AS Pattern,
NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_attributes pa ON pa.prd_id = p.prd_id
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 19
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
GROUP_CONCAT(ao.option_name SEPARATOR ', ') AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material,
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_attributes pa ON pa.prd_id = p.prd_id
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 10
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
NULL AS Ink_Type, GROUP_CONCAT(ao.option_name SEPARATOR ', ') AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material,
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_attributes pa ON pa.prd_id = p.prd_id
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 18
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
NULL AS Ink_Type, NULL AS Industry, GROUP_CONCAT(ao.option_name SEPARATOR ', ') AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material,
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_attributes pa ON pa.prd_id = p.prd_id
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id IN (1, 13, 14)
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, GROUP_CONCAT(ao.option_name) AS Themes,
NULL AS Material, NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_attributes pa ON pa.prd_id = p.prd_id
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 17
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, GROUP_CONCAT(ao.option_name) AS Material,
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_attributes pa ON pa.prd_id = p.prd_id
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 12
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material,
GROUP_CONCAT(ao.option_name) AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_attributes pa ON pa.prd_id = p.prd_id
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 2
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material,
NULL AS Pattern, GROUP_CONCAT(ao.option_name) AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_attributes pa ON pa.prd_id = p.prd_id
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 11
WHERE p.is_deleted = 'no'
group by prd_id
UNION
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color,
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material,
NULL AS Pattern, NULL AS Country_Origin, GROUP_CONCAT(ao.option_name) AS Ships_From, NULL AS prd_img_name
FROM products p
JOIN product_attributes pa ON pa.prd_id = p.prd_id
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 8
WHERE p.is_deleted = 'no'
group by prd_id

The issue you are encountering is the repeated joining to the product attributes and product options and doing full queries and getting one record returned for each component you are looking for. Also, with all the parts that are coming from the options table, you could pre-query once for each product, then return each component as one record for the PRD_ID in question.
To help optimize that component I would strongly suggest (if not already there) the following indexes...
Table Index
product_attributes ( prd_id, attr_opt_id )
attributes_options ( attr_opt_id, attr_id, option_name )
products ( is_deleted, prd_id )
product_dm ( prd_id, dm_id )
decoration_method ( dm_id, dm_name )
product_rush_title ( prd_id, rush_id )
rush_title ( rush_id, rush_title )
The indexes will be "covering" indexes so the system does not have to go back to the raw data pages to prepare the results for most of it
Then, to get each of the parts as an internal pre-query do something like...
Since the decoration and rush content come from other tables, those too can be prequeried and summarized based on just the product ID and then left-joined
SELECT
p2.prd_id,
GROUP_CONCAT( case when ao.attr_id = 19
then ao.option_name else null end SEPARATOR ', ')
AS Item_Color,
GROUP_CONCAT( case when ao.attr_id = 10
then ao.option_name else null end SEPARATOR ', ')
AS Ink_Type,
GROUP_CONCAT( case when ao.attr_id = 18
then ao.option_name else null end SEPARATOR ', ')
AS Industry,
GROUP_CONCAT( case when ao.attr_id = 17
then ao.option_name else null end SEPARATOR ', ')
AS Themes,
GROUP_CONCAT( case when ao.attr_id = 12
then ao.option_name else null end SEPARATOR ', ')
AS Material,
GROUP_CONCAT( case when ao.attr_id = 2
then ao.option_name else null end SEPARATOR ', ')
AS Pattern,
GROUP_CONCAT( case when ao.attr_id = 11
then ao.option_name else null end SEPARATOR ', ')
AS Country_Origin,
GROUP_CONCAT( case when ao.attr_id = 8
then ao.option_name else null end SEPARATOR ', ')
AS Ships_From,
GROUP_CONCAT( case when ao.attr_id IN ( 1, 13, 14 )
then ao.option_name else null end SEPARATOR ', ')
AS Size
from
products p2
JOIN product_attributes pa
ON p2.prd_id = pa.prd_id
JOIN attributes_options ao
ON pa.attr_opt_id = ao.attr_opt_id
WHERE
p2.is_deleted = 'no'
group by
p2.prd_id
Then you can roll that entire query as a subquery into your primary query but use the simplified alias reference and each pre-group concat field result
SELECT
p.prd_id,
NULL AS manu_name,
NULL AS brand_name,
NULL AS Categories,
preQuery.Item_Color,
preQuery.Ink_Type,
preQuery.Industry,
preQuery.Themes,
preQuery.Material,
preQuery.Pattern,
preQuery.Country_Origin,
preQuery.Ships_From,
preQuery.Size,
tmpDeco.Decoration_Method,
tmpRush.Rush_Production,
pi.prd_img_name
FROM
products p
LEFT JOIN product_image_p pi
ON p.prd_id = pi.prd_id
LEFT JOIN
( THE PRE-QUERY SAMPLE ABOVE ) PreQuery
ON p.prd_id = PreQuery.prd_id
LEFT JOIN
( select
p2.prd_id,
GROUP_CONCAT(decoration.dm_name SEPARATOR ', ') AS Decoration_Method
FROM
products p2
JOIN product_dm pdm
ON p2.prd_id = pdm.prd_id
JOIN decoration_method decoration ;
ON decoration.dm_id = pdm.dm_id
WHERE
p2.is_deleted = 'no'
group by
p2.prd_id ) as tmpDeco
ON p.prd_id = tmpDeco.prd_id
LEFT JOIN
( select
p2.prd_id,
GROUP_CONCAT(rush.rush_title SEPARATOR ', ') AS Rush_Production
FROM
products p2
JOIN product_rush_title prt
ON p2.prd_id = prt.prd_id
JOIN rush_title rush
ON prt.rush_id = rush.rush_id
WHERE
p2.is_deleted = 'no'
group by
p2.prd_id ) as tmpRush
ON p.prd_id = tmpRush.prd_id
WHERE
p.is_deleted = 'no'
Hopefully you are able to see the simplified context of getting all common description elements originating from the same table at once, then joining when finished based on the single alias references.
I might have a type-o or two but think it is correct otherwise in context to your needs. You also did not have any stuff for the Manu_Name, Brand_Name, Category so you will have to finish that component.
FOLLOW-UP...
Based on your latest, what I would do is add some fields to your product table to hold each of the fields. Then, create a trigger for insert/update/delete to the product attributes table when added for a product. When an impact, run just the simple sql-select group_concat() on the field in question and immediately update the main product table. Yes, this denormalizes to one extent, but completely simplifies your need to do the intensive queries and kill performance.
Take a look at my answer in this other stack question. I am creating such a similar trigger. This way, your primary table is already pre-aggregated and ready to go and the triggers should operate almost instantaneously since you would only be doing a single field for a single product.

Part of the performance issue may be due to "over-normalization". Notice how GROUP_CONCAT(ao.option_name) is not coming from the attribute table but via another JOIN. Suggest you get rid of ao and move the option_names into product_attributes.
(This is addition to #DRapp's answer, which seems, on the surface, to cover a number of ills in the query.)

Related

MYSQL query, remove row if two columns are null

I have a query that shows results like this:
Zip | Left Price | Right Price
17901 | 100.00 | null
17820 | null | 40.00
54353 | null | null
53133 | 40.00 | 542.00
How can I remove the results that have both left and price prices as null. So I wouldn't want the one here with zip 54353 to even show up in the results.
Here's how I did my query:
SELECT contacts.zip, CASE WHEN
left_return_date IS NULL AND left_delivery_date IS NOT NULL AND left_price
IS NOT NULL THEN left_price ELSE null END AS left_price, CASE WHEN
right_return_date IS NULL AND right_delivery_date IS NOT NULL AND
right_price IS NOT NULL THEN right_price ELSE null END AS right_price
FROM invoice_hearing_aids
LEFT JOIN invoices ON invoices.ID = invoice_hearing_aids.invoice_id
LEFT JOIN contacts ON contacts.id = invoices.contact_id
WHERE
trial_complete = 'Y'
AND invoices.company_id = '1'
AND invoices.date_issued >= DATE_SUB(NOW(),INTERVAL 1 YEAR)
You can add HAVING clause in the end, like this:
SELECT contacts.zip, CASE WHEN
left_return_date IS NULL AND left_delivery_date IS NOT NULL AND left_price
IS NOT NULL THEN left_price ELSE null END AS left_price, CASE WHEN
right_return_date IS NULL AND right_delivery_date IS NOT NULL AND
right_price IS NOT NULL THEN right_price ELSE null END AS right_price
FROM invoice_hearing_aids
LEFT JOIN invoices ON invoices.ID = invoice_hearing_aids.invoice_id
LEFT JOIN contacts ON contacts.id = invoices.contact_id
WHERE
trial_complete = 'Y'
AND invoices.company_id = '1'
AND invoices.date_issued >= DATE_SUB(NOW(),INTERVAL 1 YEAR)
HAVING
right_price IS NOT NULL OR left_price IS NOT NULL
This would work fine if you have relatively small number of such unwanted records (I'd do this for up to 50% of total result set size). If there are more such records, then I'd looks closer into the query and most likely will modify the condition.
Do the afct that left_price and right_price are column values you could adda where condition
SELECT contacts.zip,
CASE WHEN left_return_date IS NULL
AND left_delivery_date IS NOT NULL
AND left_price IS NOT NULL THEN left_price
ELSE null END AS left_price,
CASE WHEN right_return_date IS NULL
AND right_delivery_date IS NOT NULL
AND right_price IS NOT NULL THEN right_price
ELSE null END AS right_price
FROM invoice_hearing_aids
LEFT JOIN invoices ON invoices.ID = invoice_hearing_aids.invoice_id
LEFT JOIN contacts ON contacts.id = invoices.contact_id
WHERE
trial_complete = 'Y'
AND invoices.company_id = '1'
AND invoices.date_issued >= DATE_SUB(NOW(),INTERVAL 1 YEAR)
AND NOT (left_price IS NULL AND right_price IS NULL)

Left JOIN returning ALL NULL values when no corresponding row in right table

I have the following query and the sub query is producing a strange result when left joined. Here is what is happening (row with StoreID 1 is returning all null in joined table) and what I really want :
TABLE A
StoreID unitsales1 unitsales2 unitsales3
1 NULL NULL 6
2 12 12 12
3 12 NULL 12
TABLE B
StoreID prevunitsales1 prevunitsales2 prevunitsales3
2 NULL NULL 6
3 12 12 12
What I am getting
LEFT JOIN ON A.StoreId = B.StoreId
StoreID unitsales1 unitsales2 unitsales3 prevunitsales1 prevunitsales2 prevunitsales3
1 NULL NULL NULL NULL NULL NULL
2 12 12 12 NULL NULL 6
3 12 NULL 12 12 12 12
What I want
LEFT JOIN ON A.StoreId = B.StoreId
StoreID unitsales1 unitsales2 unitsales3 prevunitsales1 prevunitsales2 prevunitsales3
1 NULL NULL 6 NULL NULL NULL
2 12 12 12 NULL NULL 6
3 12 NULL 12 12 12 12
Here is the query:
SELECT SQL_CALC_FOUND_ROWS #storeid:=z.id,z.biz_name, z.wf_store_name, z.e_address, z.e_city, z.e_state, z.e_postal, IFNULL(total_sales - prev_total_sales,'CV') as diff_total_sales, IFNULL(d_source,'N/A') as d_source, IFNULL(unit_sales1 - prev_unit_sales1,(SELECT IFNULL(max(datetimesql),'NS') FROM storeCheckRecords WHERE store_id=#storeid AND upc=855555000019)) as diff_unit_sales1, IFNULL(unit_sales2 - prev_unit_sales2,(SELECT IFNULL(max(datetimesql),'NS') FROM storeCheckRecords WHERE store_id=#storeid AND upc=855555000022)) as diff_unit_sales2, IFNULL(unit_sales3 - prev_unit_sales3,(SELECT IFNULL(max(datetimesql),'NS') FROM storeCheckRecords WHERE store_id=#storeid AND upc=855555000025)) as diff_unit_sales3, IFNULL(unit_sales4 - prev_unit_sales4,(SELECT IFNULL(max(datetimesql),'NS') FROM storeCheckRecords WHERE store_id=#storeid AND upc=855555000028)) as diff_unit_sales4 FROM
(SELECT s1.id,s1.biz_name as biz_name, s1.wf_store_name as wf_store_name, s1.e_address as e_address,s1.e_city as e_city,s1.e_state as e_state,s1.e_postal as e_postal,sum(s2.unit_sales) as total_sales, sum(s2.unit_sales/4.28571428571) as week_avg,group_concat(DISTINCT s2.d_source separator ',') as d_source,
SUM(CASE u.id WHEN 1 THEN s2.unit_sales ELSE NULL END) AS unit_sales1,SUM(CASE u.id WHEN 2 THEN s2.unit_sales ELSE NULL END) AS unit_sales2,SUM(CASE u.id WHEN 3 THEN s2.unit_sales ELSE NULL END) AS unit_sales3,SUM(CASE u.id WHEN 4 THEN s2.unit_sales ELSE NULL END) AS unit_sales4
FROM allStores as s1
INNER JOIN storeCheckRecords AS s2
ON s1.id = s2.store_id
AND s2.datetimesql BETWEEN '2015-07-01' AND '2015-07-31'
AND s1.key_retailer LIKE 'FRESH THYME'
INNER JOIN ( SELECT 1 AS id, '855555000019' AS upc UNION SELECT 2, '855555000022' UNION SELECT 3, '855555000025' UNION SELECT 4, '855555000028' ) u ON u.upc = s2.upc
GROUP BY
s1.id) x
LEFT OUTER JOIN
(SELECT s1.id,s1.biz_name as prev_biz_name, s1.wf_store_name as prev_wf_store_name, s1.e_address as prev_e_address,s1.e_city as prev_e_city,s1.e_state as prev_e_state,s1.e_postal as prev_e_postal,sum(s2.unit_sales) as prev_total_sales, sum(s2.unit_sales/4.28571428571) as prev_week_avg,group_concat(DISTINCT s2.d_source separator ',') as prev_d_source,
SUM(CASE u.id WHEN 1 THEN s2.unit_sales ELSE 0 END) AS prev_unit_sales1,SUM(CASE u.id WHEN 2 THEN s2.unit_sales ELSE 0 END) AS prev_unit_sales2,SUM(CASE u.id WHEN 3 THEN s2.unit_sales ELSE 0 END) AS prev_unit_sales3,SUM(CASE u.id WHEN 4 THEN s2.unit_sales ELSE 0 END) AS prev_unit_sales4
FROM allStores as s1
INNER JOIN storeCheckRecords AS s2
ON s1.id = s2.store_id
AND s2.datetimesql BETWEEN '2015-06-01' AND '2015-06-30'
AND s1.key_retailer LIKE 'FRESH THYME'
INNER JOIN ( SELECT 1 AS id, '855555000019' AS upc UNION SELECT 2, '855555000022' UNION SELECT 3, '855555000025' UNION SELECT 4, '855555000028' ) u ON u.upc = s2.upc
GROUP BY
s1.id) y
ON x.id = y.id
RIGHT JOIN
(SELECT s1.id,s1.biz_name,s1.wf_store_name,s1.e_address,s1.e_city,s1.e_state,s1.e_postal
FROM allStores as s1
WHERE 1
AND s1.key_retailer LIKE 'FRESH THYME') z
ON y.id = z.id
ORDER BY biz_name ASC
LIMIT 0, 1000
What am I missing?
Comparing NULL with NULL using == never matches, which is why there is no table2 row that matches the first row of table1.
You can use <==> instead if you really want to do this.
mysql> SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
-> 1, 1, 0
mysql> SELECT 1 = 1, NULL = NULL, 1 = NULL;
-> 1, NULL, NULL

Mysql Left OUTER JOIN with Subquery (wordpress)

I am creating a query for MYSQL that will create a table from 4 tables.
SELECT xp.ID,
MAX((CASE WHEN (xum.meta_key = 'first_name') THEN xum.meta_value ELSE NULL END)) AS `first_name`,
MAX((CASE WHEN (xum.meta_key = 'last_name') THEN xum.meta_value ELSE NULL END)) AS `last_name`,
MAX((CASE WHEN (xum.meta_key = 'user_church') THEN xum.meta_value ELSE NULL END)) AS `church`,
MAX((CASE WHEN (xpm.meta_key = 'reg_user') THEN xpm.meta_value ELSE NULL END)) AS `user`,
MAX((CASE WHEN (xpm.meta_key = 'shirt_size') THEN xpm.meta_value ELSE NULL END)) AS `shirt_size`,
MAX((CASE WHEN (xpm.meta_key = 'reg_trip') THEN xpm.meta_value ELSE NULL END)) AS `trip_id`,
xp_2.post_title AS 'trip_name',
FROM xs_posts AS xp
LEFT OUTER JOIN xs_postmeta AS xpm ON xp.ID = xpm.post_id
LEFT OUTER JOIN xs_usermeta AS xum ON xum.user_id = (CASE WHEN (xpm.meta_key = 'reg_user') THEN xpm.meta_value ELSE NULL END )
LEFT OUTER JOIN xs_posts xp_2 ON xp_2.ID = (CASE WHEN (xpm.meta_key = 'reg_trip') THEN xpm.meta_value ELSE NULL END )
Where xp.post_type = 'trip_reg'
GROUP BY xp.ID
Which produces:
ID - first_name - last_name- church - user - shirt_size - trip_id - trip_name
3025 - firstname - lastname - 23 - 1 - Large - 2033 - NULL
These tables are basic wordpress tables coming from. I use the wp_posts table 2 times.
wp_usermeta
wp_posts
wp_postmeta
The problem is that I can not get the trip name to populate based on the trip_id. IE the triop_id is a post id, and I am trying to get the post title from that. That custom post type is post_mission_trip.
If I add a Where clause at the end
AND xp_2.ID IS NOT NULL
I get this as the output:
ID - first_name - last_name- church - user - shirt_size - trip_id - trip_name
3025 - NULL - NULL - NULL - NULL - NULL - 2033 - Trip Name
Just wrap the xp_2.post_title in a MAX() aggregate.
MAX(xp_2.post_title) AS `trip_name`
^^^^ ^
The problem is that the GROUP BY is collapsing the rows, and you're getting a value from an indeterminate row. That's an outer join, and the join predicate is equality on an expression that can return a NULL (the CASE expression)...
The MAX() aggregate will filter out the NULL values, and get a non-NULL value. The only way to get a NULL returned would be if all the rows had a NULL.)

mysql display results horizontally

I wrote some query and i got following query results.
createdate SITE1 SITE2 SITE3 SITE4 SITE5 SITE6 SITE7 SITE8 SITE9
10/2/2014 63 NULL NULL NULL NULL NULL NULL NULL NULL
10/2/2014 NULL NULL NULL NULL NULL NULL NULL NULL 10
10/3/2014 21 NULL NULL NULL NULL NULL NULL NULL NULL
10/3/2014 NULL NULL NULL NULL NULL NULL NULL NULL 4
Now i want to display like this.
createdate SITE1 SITE2 SITE3 SITE4 SITE5 SITE6 SITE7 SITE8 SITE9
10/2/2014 63 NULL NULL NULL NULL NULL NULL NULL 10
10/3/2014 21 NULL NULL NULL NULL NULL NULL NULL 4
Note: I already grouping SITE NAME and createdate.
Do u have any cool idea or something pls suggest me..
enter code here
select alldata.createdate, count(name),
case when name = 'SITE1' then count(1) end AS SITE1,
case when name = 'SITE2' then count(1) end AS SITE2,
case when name = 'SITE3' then count(1) end AS SITE3,
case when name = 'SITE4' then count(1) end AS SITE4,
case when name = 'SITE5' then count(1) end AS SITE5,
case when name = 'SITE6' then count(1) end AS SITE6,
case when name = 'SITE7' then count(1) end AS SITE7,
case when name = 'SITE8' then count(1) end AS SITE8,
case when name = 'SITE9' then count(1) end AS SITE9,
from
(
select total.createdate as createdate ,total.name as name from
(
select distinct dtr.* , ps.name ,DATE_FORMAT(dt.create_time,'%Y-%m-%d') as createdate from di_dtb_task_result dtr
inner join di_dtb_task_data_detail dt
on dtr.task_id = dt.task_id and dt.user_id <> 10000001
left join dtb_user_info ui
on ui.id = dt.user_id and dtr.task_id = dt.task_id
left join dtb_point_site ps
on ps.id=ui.user_point_site_id and dtr.task_id = dt.task_id
where dtr.status <> 9
-- group by dtr.status ,dtr.task_id , ui.id,ui.user_point_site_id , ps.name
order by dtr.task_id
) total
-- group by total.name , total.createdate
) alldata
group by alldata.createdate ,alldata.name
I think you may want to try max() function
select createdate, max(site1),max(site2),max(site3),max(site4),max(site5),max(site6),max(site7), max(site8),max(site9) from (..your_inner_query..) group by createdate
here you go with a sample sqlfiddle for your reference
Simplest solution:
Just add another group by sql wrapping your sql.
select alldata.createdate, sum(SITE1), sum(SITE2), sum(SITE3), sum(SITE4), sum(SITE5), sum(SITE6), sum(SITE7), sum(SITE8), sum(SITE9)
// inner select
group by alldata.createdate

Query to get lowest value that's greater than zero ans is not NULL

I've got a query:
SELECT
taskDeadline,
subtasksDeadline,
REPLACE(
LEAST(
COALESCE(t.deadline, 2147483647),
COALESCE(sub.deadline, 2147483647)
), 2147483647, NULL
) AS Deadline
FROM
tasks t
LEFT OUTER JOIN subtasks sub ON sub.task_id = t.id
This produces a result like this:
taskDeadline | subtasksDeadline | Deadline
1338501600 | 1333058400 | 1333058400
1334268000 | NULL | 1334268000
NULL | 1328050800 | 1328050800
NULL | NULL | NULL
1353798000 | 0 | 0
0 | 1353798000 | 0
I'm almost there. I've used 2147483647 as the maximum value of the data type (Mysql INT), the only problem I still have, is that if I've two values of which one is 0, I want to get the other value. I've spend some time but cannot get there. Can somebody shed a light on this?
Or just add NULLIF to your existing COALESCE -
SELECT
taskDeadline,
subtasksDeadline,
NULLIF(
LEAST(
COALESCE(NULLIF(t.deadline, 0), 2147483647),
COALESCE(NULLIF(sub.deadline, 0), 2147483647)
), 2147483647
) AS Deadline
FROM
tasks t
LEFT OUTER JOIN subtasks sub ON sub.task_id = t.id
Why not use a case statement?
SELECT
taskDeadline,
subtasksDeadline,
CASE
WHEN t.deadline IS NULL AND sub.deadline IS NULL THEN NULL
WHEN t.deadline IS NULL THEN sub.deadline
WHEN sub.deadline IS NULL THEN t.deadline
WHEN t.deadline > sub.deadline THEN sub.deadline
WHEN sub.deadline > t.deadline THEN t.deadline
WHEN sub.deadline = t.deadline THEN sub.deadline -- or this could be t.deadline
END AS Deadline
FROM
tasks t
LEFT OUTER JOIN subtasks sub
ON sub.task_id = t.id
If I understand correctly, you don't want zero values for t.deadline and sub.deadline if zero is the least. So you can convert 0 to NULL, which will be squeezed out of the COALESCE
SELECT
taskDeadline,
subtasksDeadline,
REPLACE(
LEAST(
COALESCE(IF(t.deadline = 0, NULL, t.deadline), 2147483647),
COALESCE(IF(sub.deadline = 0, NULL, sub.deadline), 2147483647)
), 2147483647, NULL
) AS Deadline
FROM
tasks t
LEFT OUTER JOIN subtasks sub ON sub.task_id = t.id
Try to use this query -
SELECT
taskDeadline,
subtasksDeadline,
LEAST(
IF(t.deadline = 0 OR t.deadline IS NULL, sub.deadline, t.deadline),
IF(sub.deadline = 0 OR sub.deadline IS NULL, t.deadline, sub.deadline)
) AS Deadline
FROM
tasks t
LEFT OUTER JOIN subtasks sub ON sub.task_id = t.id