Join Queries together in one - mysql

I have a two queries that I joined together with UNION ALL to do a count one for mobile leads and the other for web leads. But not exactly sure how to join the two results into one. Here is my query:
SELECT CAST( submitdate AS DATE ) as submitdate, COUNT( DISTINCT name, email, phone, `make` , `model` , `mdlyr` , `miles` ) AS webcount FROM leads WHERE email <> '' and mobile = '0' GROUP BY CAST( submitdate AS DATE )
UNION ALL
SELECT CAST( submitdate AS DATE ) as submitdate, COUNT( DISTINCT name, email, phone, `make` , `model` , `mdlyr` , `miles` ) AS mobilecount FROM leads WHERE email <> '' and mobile = '1' GROUP BY CAST( submitdate AS DATE )
But my results are two columns that says submitdate, webcount and the dates are duplicated and with counts next to them like this:
submitdate | webcount
2014-03-19 | 30
2014-03-19 | 15
2014-03-18 | 59
2014-03-18 | 37
When I am trying to get it to look like this:
submitdate | webcount | mobilecount
2014-03-19 | 30 | 15
2014-03-18 | 59 | 37
What am I doing wrong?

Here is a pivot approach. Use your union, but as a "PreQuery". I added one extra column to identify the origin as web or mobile by a character. From that, I use that at the outer level and do a group by date, but a sum of whatever count, but only based on the web or mobile flag value.
select
PQ.submitdate,
sum( case when PQ.leadOrigin = 'W' then PQ.DateCnt else 0 end ) as WebCount,
sum( case when PQ.leadOrigin = 'M' then PQ.DateCnt else 0 end ) as MobileCount
from
( SELECT
CAST( submitdate AS DATE ) as submitdate,
MAX( 'W' ) as leadOrigin,
COUNT( DISTINCT name, email, phone, `make` , `model` , `mdlyr` , `miles` ) AS DateCnt
FROM
leads
WHERE
email <> ''
and mobile = '0'
GROUP BY
CAST( submitdate AS DATE )
UNION ALL
SELECT
CAST( submitdate AS DATE ) as submitdate,
MAX( 'M' ) as leadOrigin,
COUNT( DISTINCT name, email, phone, `make` , `model` , `mdlyr` , `miles` ) AS DateCnt
FROM
leads
WHERE email <> ''
and mobile = '1'
GROUP BY CAST( submitdate AS DATE ) ) PQ
group by
PQ.submitdate

I was able to do this query:
SELECT a.submitdate, b.webcount, c.mobilecount
FROM (
SELECT DISTINCT CAST( submitdate AS DATE ) AS submitdate FROM leads) AS a
INNER JOIN
(SELECT CAST( submitdate AS DATE ) AS submitdate, COUNT( DISTINCT name, email, phone, `make` , `model` , `mdlyr` , `miles` ) AS webcount FROM leads WHERE email <> '' AND mobile = '0' GROUP BY CAST( submitdate AS DATE )) AS b ON a.submitdate = b.submitdate
INNER JOIN
(SELECT CAST( submitdate AS DATE ) AS submitdate, COUNT( DISTINCT name, email, phone, `make` , `model` , `mdlyr` , `miles` ) AS mobilecount FROM leads WHERE email <> '' AND mobile = '1' GROUP BY CAST( submitdate AS DATE )) AS c ON b.submitdate = c.submitdate
ORDER BY a.submitdate DESC
But it only gives me dates from 3/16/2014, which is when Mobile has a count higher than 0. Is there something to add to this that will include all dates and default to 0 if there is none?

Related

2 SQL queries at once

How can I concatenate these two queries, so that I can have 3 columns in my result: postcode, memberCount and placeCount
SELECT LEFT(`delivery_postcode`, 2) as `postcode`, count(`delivery_postcode`) as `count`
FROM `customer_cards`
WHERE `delivery_postcode` IS NOT NULL
AND `delivery_postcode` <> ''
GROUP BY `postcode`
ORDER BY `count` DESC
and
SELECT LEFT(`placePostcode`, 2) as `postcode`, count(`placePostcode`) as `placeCount`
FROM `RestaurantsForGoogleMaps`
WHERE `placePostcode` IS NOT NULL
AND `placePostcode` <> ''
GROUP BY `postcode`
ORDER BY `placeCount` DESC
At the moment my results look like the following, for either query
postcode | count/placeCount
------------------------
SW | 817
W1 | 533
EC | 395
Something like this should work:
SELECT LEFT(`delivery_postcode`, 2) as `postcode`
, count(`delivery_postcode`) as `count`
, pc.placeCount
FROM `customer_cards` cc
LEFT JOIN (
SELECT LEFT(`placePostcode`, 2) as `postcode`,
count(`placePostcode`) as `placeCount`
FROM `RestaurantsForGoogleMaps`
WHERE `placePostcode` IS NOT NULL
AND `placePostcode` <> ''
GROUP BY `postcode`
) pc
on pc.postcode = LEFT(cc.delivery_postcode, 2)
WHERE `delivery_postcode` IS NOT NULL
AND `delivery_postcode` <> ''
GROUP BY `postcode`
ORDER BY `count` DESC
SELECT postcode,count,placecount FROM (SELECT LEFT(`delivery_postcode`, 2) as `postcode`, count(`delivery_postcode`) as `count`, 0 as `placecount`
FROM `customer_cards`
WHERE `delivery_postcode` IS NOT NULL
AND `delivery_postcode` <> ''
GROUP BY `postcode`
UNION
SELECT LEFT(`placePostcode`, 2) as `postcode`, count(`placePostcode`) as `placecount`,0 as `count`
FROM `RestaurantsForGoogleMaps`
WHERE `placePostcode` IS NOT NULL
AND `placePostcode` <> ''
GROUP BY `postcode` ) ORDER BY count desc
At the moment my results look like the following, for either query
;WITH PC1 AS (
SELECT LEFT(`delivery_postcode`, 2) as `postcode`, count(`delivery_postcode`) as `count`
FROM `customer_cards`
WHERE `delivery_postcode` IS NOT NULL
AND `delivery_postcode` <> ''
GROUP BY `postcode`
ORDER BY `count` DESC
),
PC2 AS (
SELECT LEFT(`placePostcode`, 2) as `postcode`, count(`placePostcode`) as `placeCount`
FROM `RestaurantsForGoogleMaps`
WHERE `placePostcode` IS NOT NULL
AND `placePostcode` <> ''
GROUP BY `postcode`
ORDER BY `placeCount` DESC
)
SELECT a.postcode, a.count,b.placeCount
FROM PC1 a
LEFT JOIN PC2 b
ON a.postcode = b.postcode
Create both queries as an inline views and then join on postcode. This assumes both queries return the desired results and that POST CODE is the key on which to join and there are no other attributes needing to complete the join properly. It also assumes the post code would be in both tables.
If not, then we have to replicate the join as right and left and union the results together.
SELECT A.postcode, A.mcount, B.placecount
FROM
(SELECT LEFT(delivery_postcode, 2) as postcode, count(delivery_postcode) as mcount
FROM customer_cards
WHERE delivery_postcode IS NOT NULL
AND delivery_postcode <> ''
GROUP BY LEFT(delivery_postcode, 2)) A
INNER JOIN (
SELECT LEFT(placePostcode, 2) as postcode, count(placePostcode) as placeCount
FROM RestaurantsForGoogleMaps
WHERE placePostcode IS NOT NULL
AND placePostcode <> ''
GROUP BY LEFT(placePostcode, 2)) B
on A.postcode = B.postcode
order by A.postcode

MySQL ORDER BY Aggregate column returning incorrect results

Im struggling to get this query to be able to order by stakes correctly - it returns values that are neither desc or asc. It does work with wins if I use order by. Perhaps MySQL did not evaluate the sort order at the time it was building the aggregation?
I've stripped out some of the full names to make it less tedious to read.
SELECT a.b AS t , COUNT( c.aID ) AS r ,
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) AS wins ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) / COUNT( c.aID ) ) *100, 0 ) , '%'
) AS Percent ,
FORMAT( SUM( c.StakeWon ) , 0 ) AS stakes
FROM c
INNER JOIN a ON c.aID = a.aID
INNER JOIN d ON c.dID = d.dID
WHERE d.w >= STR_TO_DATE( '2012,07,01', '%Y,%m,%d' )
AND d.w < STR_TO_DATE( '2012,07,01', '%Y,%m,%d' ) + INTERVAL 1
MONTH
GROUP BY a.b
ORDER BY stakes DESC`
It also doesnt work if I order by Percent. I didnt want to ask this question here but this is driving me crazy.
It would help if you show some of the result, but you must sort the stakes before you format it. Then you really sort the numeric value rather than the formatted string.
Here is an example SQL Fiddle how it would go wrong.
The numeric values are not sorted descending because of the formatting
100
10,000,000
-5,000,005
So you would do something like
...
FORMAT( SUM( c.StakeWon ) , 0 ) AS stakes ,
SUM( c.StakeWon ) AS stakes_num
...
ORDER BY stakes_num desc
Example how it would work: SQL Fiddle
Try using this whole expression
COUNT( c.aID ) AS r ,
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) AS wins ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) / COUNT( c.aID ) ) *100, 0 ) , '%'
) AS Percent ,
FORMAT( SUM( c.StakeWon ) , 0 )
in the order by clause instead of alias. My observation is, Alias doesn't work this way
Probably like this
SELECT a.b AS t , COUNT( c.aID ) AS r ,
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) AS wins ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) / COUNT( c.aID ) ) *100, 0 ) , '%'
) AS Percent ,
FORMAT( SUM( c.StakeWon ) , 0 ) AS stakes
FROM c
INNER JOIN a ON c.aID = a.aID
INNER JOIN d ON c.dID = d.dID
WHERE d.w >= STR_TO_DATE( '2012,07,01', '%Y,%m,%d' )
AND d.w < STR_TO_DATE( '2012,07,01', '%Y,%m,%d' ) + INTERVAL 1
MONTH
GROUP BY a.b
ORDER BY COUNT( c.aID ) AS r ,
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) AS wins ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) / COUNT( c.aID ) ) *100, 0 ) , '%'
) AS Percent ,
FORMAT( SUM( c.StakeWon ) , 0 ) DESC`

MySQL: Calculate the duration for multiple statuses

I have a database that contains member information for a club. Each member at any time can be one of three distinct statuses (active, veteran, associate). I have it broken down into three tables. The member table, with all the member information, the status table with the status_name and status_id and a grid table which includes the member_id, status_id, date_from and date_to.
I am trying to calculate the amount of time a member has spent at each status. I am currently calculating the total time that the member has spent in the "active" status via the following query:
SELECT first_name, last_name,
(DATE_FORMAT( FROM_DAYS( SUM( DATEDIFF( IFNULL( q.date_to, NOW() ) , q.date_from ) ) ) , "%Y" ) +0) as service_years
FROM member a
LEFT JOIN member_status q on a.id = q.member_id AND q.status_id = 1
GROUP BY a.id
I know that I can pull the total time that the person has been a member by leaving off the AND in the left join, however I can't figure out a way to calculate the time for each status in a single query.
My ideal result would be along the lines of:
-----------------------------------------------------------
|member_name | active_years | veteran_years | total_years |
-----------------------------------------------------------
|name | 5 | 5 | 10 |
-----------------------------------------------------------
Is there a way to accomplish what I'm looking for in a single query?
Assuming 1=active and 2=veteran, something like this should work:
SELECT first_name, last_name,
(DATE_FORMAT( FROM_DAYS( SUM( case when q.status_id = 1 then DATEDIFF( IFNULL( q.date_to, NOW() ) , q.date_from ) ) else 0 end ) , "%Y" ) +0) as active_years,
(DATE_FORMAT( FROM_DAYS( SUM( case when q.status_id = 2 then DATEDIFF( IFNULL( q.date_to, NOW() ) , q.date_from ) ) else 0 end ) , "%Y" ) +0) as veteran_years,
(DATE_FORMAT( FROM_DAYS( SUM( DATEDIFF( IFNULL( q.date_to, NOW() ) , q.date_from ) ) ) , "%Y" ) +0) as total_years
FROM member a
LEFT JOIN member_status q on a.id = q.member_id AND q.status_id in (1,2)
GROUP BY a.id
Another option is to join the member_status table more than once.
You should be able to do something like this which uses a CASE statement to determine the status name and then calculates the total number of years based on the status:
SELECT first_name,
last_name,
CASE WHEN status_name = 'active'
then (DATE_FORMAT( FROM_DAYS( SUM( DATEDIFF( IFNULL( q.date_to, NOW() ) , q.date_from ) ) ) , "%Y" ) +0) end as active_years,
CASE WHEN status_name = 'veteran'
then (DATE_FORMAT( FROM_DAYS( SUM( DATEDIFF( IFNULL( q.date_to, NOW() ) , q.date_from ) ) ) , "%Y" ) +0) end as active_years,
(DATE_FORMAT( FROM_DAYS( SUM( DATEDIFF( IFNULL( q.date_to, NOW() ) , q.date_from ) ) ) , "%Y" ) +0) as total_years,
FROM member a
LEFT JOIN member_status q
on a.id = q.member_id
AND q.status_id = 1
GROUP BY a.id, a.first_name, a.last_name
if you post some sample data it will be easier to determine the proper query

How to merge the result of this 2 queries in mysql server

I am actually stuck in merging the result of this two queries:
first query:
SELECT c.code, c.name, pc.sku, pc.cat_code, pp.title
FROM `cat_parent` cp, cat c, prod_cat pc, products pp
WHERE c.code = cp.cat_code
AND cp.cat_code = pc.cat_code
AND pp.sku = pc.sku
AND cp.parent_code = 01110
AND hide =0
The result I get is:
Second query:
SELECT `sku` , `update_date` , `description` , count( * ) AS total_sold
FROM `orderline`
WHERE `update_date` >= ( DATE_ADD(CURDATE( ) , INTERVAL -14 DAY ) )
AND `update_date` <= ( DATE_ADD(CURDATE( ) , INTERVAL -7 DAY ) )
GROUP BY left( sku, 7 )
ORDER BY total_sold DESC
The result:
The question I want to ask that how can I get the result by filtering the sku available in both tables.
Just bit confused on that part....any ideas will be appreciated.
This is only part of the data. there is heaps of data. Yes, I want to merge the both tables and want to find the common sku available in both tables.
My expected result will be sku, title, total sold.
Thanks, anyway I managed to get around to get the result.
My final query:
SELECT * FROM (
SELECT sku , update_date , description FROM orderline WHERE
update_date >= '2012-03-06' AND update_date <= '2012-03-07' )g
JOIN (
SELECT c.code, c.name, pc.sku, pc.cat_code FROM cat_parent cp, cat
c, prod_cat pc, products pp WHERE c.code = cp.cat_code AND cp.cat_code
= pc.cat_code AND pp.sku = pc.sku AND cp.parent_code =01110 AND hide =0 )p ON left( g.sku, 7 ) = left( p.sku, 7 )
Something like this -
SELECT
`c`.`code`, `c`.`name`, `pc`.`sku`, `pc`.`cat_code`, `pp.title`,
`ol`.`sku`, `ol`.`update_date`, `ol`.`description`, COUNT(*) AS `total_sold`
FROM `cat_parent` `cp`
INNER JOIN `cat` `c`
ON `c`.`code` = `cp`.`cat_code`
INNER JOIN `prod_cat` `pc`
ON `cp`.`cat_code` = `pc`.`cat_code`
INNER JOIN `products` `pp`
ON `pp`.`sku` = `pc`.`sku`
INNER JOIN `orderline` `ol`
ON LEFT(`pc`.`sku`, 7) = LEFT(`ol`.`sku`, 7)
WHERE `cp`.`parent_code` = 01110
AND `hide` = 0
AND `ol`.`update_date` >= ( DATE_ADD(CURDATE( ) , INTERVAL -14 DAY ) )
AND `ol`.`update_date` <= ( DATE_ADD(CURDATE( ) , INTERVAL -7 DAY ) )
GROUP BY left( `ol`.`sku`, 7 )
ORDER BY `total_sold` DESC

mysql date-format returns null

I have the following SQL query. It returns NULL for the 'invoice_date'.
SELECT * , fk_uid AS userId, fk_ivid AS invoice_uid, (
SELECT company
FROM tbl_users
WHERE pk_uid = userId
) AS invoice_customer, (
SELECT DATE_FORMAT( '%d/%m/%y', purchased ) AS invoice_date
FROM _invoices
WHERE invoice_uid = invoice_uid
LIMIT 1
) AS invoice_date
FROM tbl_statement_items
WHERE statement_generated = '1'
AND fk_statementId = '1'
LIMIT 0 , 30
Any help would be appriciated.
Thanks
You have inverted date_format parameters order.