mySQL UNION fault - mysql

Im having trouble with a sql join involving a union. I'm trying to pull a COUNT and a field from 2 tables but getting an error.
The query:
$sql_result7 = mysql_query("(SELECT COUNT (*) as alertcount, date as alertdate FROM alerts WHERE to_id='$id' AND date > '$lastcheck') UNION (SELECT COUNT (*) as mailcount, date maildate FROM mobmail WHERE to_id='$id' AND to_del=0 AND seen = '0')", $db);
$rs7 = mysql_fetch_array($sql_result7);
$alerts = $rs7[alertcount];
$mails = $rs7[mailcount];
$last_alert = $rs7[alertdate];
$last_mail = $rs7[maildate];
Is it something to do with the date as alertdate part?
The error im getting is:
Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource

Besides the space between COUNT and (*), there is another issue. You can't use $rs7[mailcount] nor $rs7[maildate] in your PHP code because your query is equivalent to:
SELECT
COUNT(*) as alertcount
, date as alertdate
FROM alerts
WHERE to_id = '$id'
AND date > '$lastcheck'
UNION
SELECT
COUNT(*) --- No "as mailcount" here
, date --- No "as maildate" either
FROM mobmail
WHERE to_id = '$id'
AND to_del = 0
AND seen = '0'
and will return two rows and only 2 columns:
alertcount | alertdate
-----------|------------
24 | 2012-01-04
73 | 2011-11-11
Two ways to solve this problem:
Either keep the query (changing the UNION to UNION ALL to ensure that you always get 2 rows) and chnage the PHP to use the 2 rows.
Or change the query to:
SELECT alertcount, alertdate, mailcount, maildate
FROM
( SELECT
COUNT(*) AS alertcount
, date AS alertdate
FROM alerts
WHERE to_id = '$id'
AND date > '$lastcheck'
) AS a
CROSS JOIN
( SELECT
COUNT(*) AS mailcount
, date AS maildate
FROM mobmail
WHERE to_id = '$id'
AND to_del = 0
AND seen = '0'
) AS b

Related

mySql different between 2 allies

im query mysql data for mismatch 2 different table data, i already trying getting data on picture bellow. now i need to compare sell_qty and sold_qty allies.
please check out this query
SELECT
purchase_lines.`product_id`,
(SELECT SUM(`quantity`) FROM `purchase_lines`
WHERE transaction_sell_lines.product_id = purchase_lines.product_id GROUP BY product_id LIMIT 1 ) as purchase_qty,
(SELECT SUM(`quantity`) FROM `transaction_sell_lines`
WHERE transaction_sell_lines.product_id = purchase_lines.product_id GROUP BY product_id LIMIT 1 ) as sell_qty,
(SELECT SUM(`quantity_sold`) FROM `purchase_lines`
WHERE transaction_sell_lines.product_id = purchase_lines.product_id GROUP BY product_id LIMIT 1 ) as sold_qty,
variation_location_details.qty_available as avaiable_qty
FROM
`purchase_lines`,
variation_location_details,
transaction_sell_lines
WHERE
purchase_lines.product_id = variation_location_details.product_id
AND
variation_location_details.product_id = transaction_sell_lines.product_id
GROUP BY
variation_location_details.product_id
I need to different between on where clause
sell_qty != sold quantity

MySQL GROUP unless value equals 0

I would like a query that groups the results together unless the value of job_num = 0 but I have been unable to work out how to do it.
This is my query as it stands (and doesn't work, I get a SQL error)...
SELECT SQL_CALC_FOUND_ROWS * FROM calls
WHERE parent_id = '$term' GROUP BY IF (job_num != 0)
ORDER BY date_start DESC LIMIT $page_position, $item_per_page
I have tried replacing job_num != 0 with job_num IS NOT NULL and get the same result.
The rest of the query works fine until I tried to exclude the job_num != 0
This a simplified version of the table
id | call_ref | job_num
_______________________
1 | 123445 | 2389
_______________________
2 | 342537 | 0
_______________________
3 | 876483 | 2389
_______________________
4 | 644686 | 5643
_______________________
5 | 654532 | 0
I would like to group the rows where the job_num != 0 but I still want to display the rows where job_num = 0 just not grouped together. The call_ref is not unique and there are a further 31 columns in the table I need the values of.
Using the above example rows with ids 1 and 3 would be grouped and 2,4 and 5 would still return results but not grouped.
The results I would like...
1 and 3 grouped (because the job_nums are the same but != 0)
2, 4, 5 not grouped
Can you try it with UNION?
(SELECT SQL_CALC_FOUND_ROWS * FROM calls
WHERE parent_id = '$term' where job_num != 0 GROUP BY (job_num)
ORDER BY date_start DESC LIMIT $page_position, $item_per_page)
UNION
(SELECT SQL_CALC_FOUND_ROWS * FROM calls
WHERE parent_id = '$term' where job_num = 0
ORDER BY date_start DESC LIMIT $page_position, $item_per_page);
if you use this request in PHP code Try
SELECT SQL_CALC_FOUND_ROWS FROM calls
WHERE parent_id = \'$term\' GROUP BY IF job_num <> 0
ORDER BY date_start DESC LIMIT $page_position, $item_per_page;
Try this one
SELECT *
FROM
(SELECT SQL_CALC_FOUND_ROWS *
FROM calls
WHERE parent_id = '$term'
AND job_num != 0
GROUP BY job_num
UNION SELECT SQL_CALC_FOUND_ROWS *
FROM calls
WHERE parent_id = '$term'
AND job_num = 0) AS T
ORDER BY date_start DESC LIMIT $page_position,
$item_per_page
Based on this comment:
#mcNets because ideally I'd like to display the results with job_num
!= 0, I just don't want the results with that value grouped together
You do not want group by (although I don't understand what "that value" refers to). I do note this is in direct contradiction of the first sentence of the question.
Does this do what you want?
SELECT SQL_CALC_FOUND_ROWS c.*
FROM calls c
WHERE c.parent_id = '$term' AND job_num <> 0
ORDER BY date_start DESC
LIMIT $page_position, $item_per_page;
EDIT:
It occurs to me that you might just want rows with the value of 0 to appear together and the rest to appear together. If that is the case, put the condition in the ORDER BY:
SELECT SQL_CALC_FOUND_ROWS c.*
FROM calls c
WHERE c.parent_id = '$term'
ORDER BY (job_num = 0), date_start DESC
LIMIT $page_position, $item_per_page;
You can use a derived table for the main query, then LEFT JOIN it on to the table that you want to display multiple rows for. For example:
SELECT *
FROM (
SELECT a.account_id 'CRM ID', a.lead_status 'Status', a.account_name 'Client Name', DATE_FORMAT(DATE_ADD(FROM_UNIXTIME(0), INTERVAL a.date_of_birth SECOND), '%d-%m-%Y') AS 'DOB', a.postcode 'Postcode',
a.phone 'Phone #.', a.email 'Email', IFNULL(i.invoice_date, 'Never') AS 'Last Invoice'
FROM mydb.invoices i
RIGHT JOIN mydb.members m ON i.member_id = m.member_id
RIGHT JOIN mydb.accounts a ON m.crm_id = a.account_id
WHERE (i.invoice_status LIKE 'SAVE%' OR i.invoice_date IS NULL)
AND a.lead_status IN ('SIGNED UP', 'BILLING')
AND a.account_position != 'DELETED'
GROUP BY a.account_id
) x
LEFT JOIN mydb.account_owners o ON x.`CRM ID` = o.account_id
In this query, the final LEFT JOIN is the one that makes the row display more than once, despite the GROUP BY, e.g.:
Aside: ignore the fact that the columns in the above query have got 'friendly' names. This query is taken from a reporting tool that shows the columns based upon what SQL returns :)

Fetch only 2 results, one for each different value of a concrete field

In a MYSQL table with those 5 fields: id, user_id, date, type, uid where type can be 1 or 2, I'm looking for a single query where I can fetch 2 results, one for type=1 and another one for type=2 based on date field.
Right now i have the following query which only gives me the last uid without taking care of the type field.
SELECT t.uid
FROM table AS t
WHERE t.user_id = 666
ORDER BY t.date
DESC LIMIT 1
Does anyone know how should modify this query so i can get the last uid for type=1 and the last one for type=2 based on date field? I would like to keep a a single query
Union all is probably the simplest method:
(select t.*
from t
where t.user_id = 666 and t.type = 1
order by date desc
limit 1
) union all
(select t.*
from t
where t.user_id = 666 and t.type = 2
order by date desc
limit 1
)
Finally i updated the query following this "paradigm":
http://dev.mysql.com/doc/refman/5.7/en/example-maximum-column-group-row.html
http://jan.kneschke.de/projects/mysql/groupwise-max/
This is how the query ended up:
SELECT s1.type, s1.uid
FROM t AS s1
LEFT JOIN t AS s2 ON s1.type = s2.type AND s1.date < s2.date
WHERE s2.date IS NULL;
Here's a visual example: http://hastebin.com/ibinidasuw.vhdl
Credits are for snoyes from #sql on Freenode. :)

mysql : Get latest value and sum of values from previous hour

I would like to return a product together with its latest value and values from last hour.
I have a product-table :
id, name, type (and so on)...
I have a values-table :
id_prod, timestamp, value
Something like :
12:00:00 = 10
12:15:00 = 10
12:30:00 = 10
12:45:00 = 10
13:00:00 = 10
13:15:00 = 10
13:30:00 = 10
I would like a query that returns the latest value (13:30:00) together with the sum of values one hour back. This should return:
time = 13:30:00
latestread = 10
lasthour = 40
What I almost got working was:
SELECT *,
(SELECT value FROM values S WHERE id_prod=P.id
ORDER BY timestamp DESC LIMIT 1) as latestread,
(SELECT sum(value) FROM values WHERE id_prod=D.id and
date_created>SUBTIME(S.date_created,'01:00:00')) as trendread
FROM prod P ORDER BY name
But this fails with "Unknown column 'S.date_created' in 'where clause'"
Any suggestions?
If I understand correctly what you're trying to do, then You would have something like:
SELECT p.id, max(date_created), sum(value), mv.max_value
FROM product p
JOIN values v on p.id = v.product_id
JOIN (SELECT product_id, value as max_value
FROM values v2
WHERE date_created = (SELECT max(date_created) FROM values WHERE product_id=v2.product_id)) mv on product_id=p.id
WHERE date_created between DATE_SUB(now(), INTERVAL 1 HOUR)) and now()
GROUP BY p.id
ORDER BY p.id
Aleks G and mhasan gave solutions, but not the reason why this fails. The reason this fails is because the alias S is not known inside the subquery. Subqueries have no knowledge about the tables outside their scope.
You have missed providing alias for table Values in subquery below
SELECT *,
(SELECT value FROM values S WHERE id_prod=P.id
ORDER BY timestamp DESC LIMIT 1) as latestread,
(SELECT sum(value) FROM values S WHERE id_prod=P.id and
date_created>SUBTIME(S.date_created,'01:00:00')) as trendread
FROM prod P ORDER BY name
I think this is the query that you are trying to write:
SELECT p.*,
(SELECT v.value
FROM values v
WHERE v.id_prod = p.id
ORDER BY v.timestamp DESC
LIMIT 1
) as latestread,
(SELECT sum(v.value)
FROM values v
WHERE v.id_prod = p.id and
v.timestamp > SUBTIME(now(), '01:00:00')
) as trendread
FROM prod p
ORDER BY p.name;
This changes all the aliases to be abbreviations for the table name. It also fixes the expression for the last hour by using now() and gets rid of date_created which doesn't seem to be in either table based on the question. The query conveniently assumes that timestamp is a datetime. If it is a unix timestamp, then somewhat different time logic is necessary.
This should be reasonably efficient with an index on values(id_prod, timestamp, value).

Get the count of group by results

I am getting count of some column by using group by. It returns results of the form,
col1 count
date1 1
date2 2
I would like to further count on this result so that it returns 3.
How would I go about accomplishing this?
SELECT t.p_date
,count(t.p_date) AS saturday
FROM t_p_booking t
WHERE t.p_id IN (
220
,221
)
AND dayofweek(t.p_date) = 7
AND date_format(t.p_date, '%Y%m') = : ccyymm
GROUP BY t.p_date
Add WITH ROLLUP to the end of your GROUP BY clause
Would that not just be:
SELECT count(*)
FROM t_p_booking t
WHERE t.p_id IN (
220
,221
)
AND dayofweek(t.p_date) = 7
AND date_format(t.p_date, '%Y%m') = : ccyymm
GROUP BY t.p_date