This query always returns at least one row even if none is found
(
SELECT accounting.time, enclosure.enc_id_, enclosure.txt, accounting.amount AS sum, SUM(ROUND(vatcode.percent/(100+vatcode.percent)*accounting.amount)) AS sum_vat
FROM accounting
INNER JOIN enclosure ON enclosure.id=accounting.enc_id
LEFT JOIN vatcode ON vatcode.id=accounting.vatcode_id
WHERE accounting.account_id='10'
)
UNION (
SELECT accounting.time, enclosure.enc_id_, enclosure.txt, accounting.amount*-1 AS sum, NULL AS sum_vat
FROM accounting
INNER JOIN enclosure ON enclosure.id=accounting.enc_id
WHERE accounting.accountoff_id='10'
) ORDER BY time
I know that the error occurs in the second select here ... , NULL AS sum_vat.. If I remove it I get an error about not having the same statements in both select? How can this be solved?
return
Array
(
[time] => 0
[enc_id_] => 0
[txt] =>
[sum] => 0
[sum_vat] =>
)
If you use an aggregate without a group by, the aggregate will run over the entire table, always returning a single row. For example,
select max(price) from items where group = 'Servers'
returns a single row with the highest price. MySQL is the only database that allows other columns without a group by:
select name, max(price) from items where group = 'Servers'
But confusingly, it would just put a random value in name column; the name here won't be the name of the highest priced server.
In your case, the obvious solution is to add a group by to the first part of the union:
SELECT accounting.time, enclosure.enc_id_, enclosure.txt, accounting.amount sum,
SUM(ROUND(vatcode.percent/(100+vatcode.percent)*accounting.amount)) sum_vat
FROM accounting
INNER JOIN enclosure ON enclosure.id=accounting.enc_id
LEFT JOIN vatcode ON vatcode.id=accounting.vatcode_id
WHERE accounting.account_id='10'
GROUP BY accounting.time, enclosure.enc_id_, enclosure.txt, accounting.amount
Related
I am having 3 tables namely
category
case
cost
office_id
category_id
linked to >
category_id
case_number
linked to >
case_number
total_cost
Problem:
I need to fetch the total number of case and their respective cost for every office id which is there in category table
Query I have written:
select cm_c_d.case_number,cm_c.office_id,count(*) as case_count from categories as cm_c
join case as cm_c_d on cm_c.category_id = cm_c_d.category_id
join cost on cm_c_d.case_number = cost.case_number group by office_id;
but I don't think this will provide the desired result as joining all the three tables will increase the row count.
Updated SQL query:
select cm_c.office_id
, count(DISTINCT cm_costs.case_number) as case_count
, SUM(total_charge) AS overall_cost
from cm_categories as cm_c
JOIN cm_case_details as cm_c_d
on cm_c.category_id = cm_c_d.category_id
join cm_costs
on cm_c_d.case_number = cm_costs.case_number
group by cm_c.office_id
;
If you want distinct case count (adjusted with the new table names):
SELECT cm_c.office_id
, COUNT(DISTINCT cm_costs.case_number) AS case_count
, SUM(total_charge) AS overall_cost
FROM cm_categories AS cm_c
JOIN cm_case_details AS cm_c_d ON cm_c.category_id = cm_c_d.category_id
JOIN cm_costs ON cm_c_d.case_number = cm_costs.case_number
GROUP BY cm_c.office_id
;
COUNT(DISTINCT x) means count the distinct number of x values for each group.
Also notice we needed to quote the case table name. As mentioned in prior comments, that's a reserved word. I suggest avoiding use of reserved words as identifiers (table, column, etc names).
I've removed case_number from your SELECT list because it's not functionally dependent on the GROUP BY terms. That means the design/query does not guarantee that there is at most one case_number for each office_id.
If you want a case_number in the select list, you would need to use a form of aggregation (like COUNT), as follows:
SELECT cm_c.office_id
, COUNT(DISTINCT cm_costs.case_number) AS case_count
, SUM(total_charge) AS overall_cost
, MIN(cost.case_number) AS some_case_number
, GROUP_CONCAT(cost.case_number) AS all_cases
FROM cm_categories AS cm_c
JOIN cm_case_details AS cm_c_d ON cm_c.category_id = cm_c_d.category_id
JOIN cm_costs ON cm_c_d.case_number = cm_costs.case_number
GROUP BY cm_c.office_id
;
Be careful of GROUP_CONCAT for very large sets, since that result column width could get rather wide.
Here's the test case, with necessary adjustments:
Test case
For more detail on GROUP BY and functional dependence, see the following links:
group-by-handling
group-by-functional-dependence
My code sample for get total total_stamp, i need with active and inactive. My stamp table have current_status row for active and inactive
SELECT r.*
, COUNT(s.current_status) total_stamp
FROM tbl_registers r
LEFT
JOIN tbl_stamps s
ON r.register_id = s.register_id
WHERE r.ins_id = 1
GROUP
BY r.register_id
ORDER BY r.register_name_en ASC
, s.stamp_name_en ASC
Current output like that, I need another more column line one is total_active another is total inactive with single query.
SELECT r.*,
COUNT(s.current_status),
SUM(current_status='something meaning active') active,
SUM(current_status='something meaning inactive') inactive,
...
should do the trick. Why? because expressions like current_status='something meaning inactive' in MySQL have the value 0 meaning false, or 1 meaning true. So SUM() adds up the number of true items.
I think the best way to achieve this would be to split your LEFT JOIN up into two separate LEFT JOINS. One to the table where active and another where inactive. This way you will be able to sum the three separately. Does that make sense? Something like this:
SELECT r.*, sActive.total + sInactive.total as total_stamp, sActive.total as active_stamp, sInactive.total as inactive_stamp
FROM tbl_registers as r
LEFT JOIN (
SELECT register_id, COUNT(*) as total
FROM tbl_stamps
WHERE s.current_status = 'active'
GROUP BY register_id
) as sActive ON sActive.register_id = r.register_id
LEFT JOIN (
SELECT register_id, COUNT(*) as total
FROM tbl_stamps
WHERE s.current_status = 'inactive'
GROUP BY register_id
) as sInactive ON sInactive.register_id = r.register_id
GROUP BY r.register_id
I have the following tables:
URLInfo(uid, url, host_ip)
Stats(sid, url, country, platform, source, count)
An "URLInfo" has many "Stats", and I want to obtain the sum of the count attribute for a given "URLInfo". This is easy, and can be done with a join query.
However, for my particular case, when there's no corresponding entry in the "Stats" table, I want to obtain a value of 0 for the sum. sum being an aggregate function entirely ignores the null value, and I cannot come up with the right query.
How can I do this?
You can use LEFT JOIN, e.g.:
SELECT u.uid, SUM(IFNULL(s.sid, 0)) AS stats
FROM urlinfo u LEFT JOIN stats s ON u.url = s.url
GROUP BY u.uid;
You can use the COALESCE function. It returns the first non-NULL value from the list.
To find the count for a single url, this should do the trick:
SELECT coalesce(sum(count), 0) as total_count
FROM urlinfo INNER JOIN stats ON urlinfo.id = stats.url
WHERE urlinfo.id = <your_url_id>;
For all the urls, you could write the query as:
SELECT coalesce(sum(count), 0) as total_count
FROM urlinfo LEFT JOIN stats ON urlinfo.id = stats.url
GROOUP BY urlinfo.id;
I have couple tables joined in MySQL - one has many others.
And try to select items from one, ordered by min values from another table.
Without grouping in seems to be like this:
Code:
select `catalog_products`.id
, `catalog_products`.alias
, `tmpKits`.`minPrice`
from `catalog_products`
left join `product_kits` on `product_kits`.`product_id` = `catalog_products`.`id`
left join (
SELECT MIN(new_price) AS minPrice, id FROM product_kits GROUP BY id
) AS tmpKits on `tmpKits`.`id` = `product_kits`.`id`
where `category_id` in ('62')
order by product_kits.new_price ASC
Result:
But when I add group by, I get this:
Code:
select `catalog_products`.id
, `catalog_products`.alias
, `tmpKits`.`minPrice`
from `catalog_products`
left join `product_kits` on `product_kits`.`product_id` = `catalog_products`.`id`
left join (
SELECT MIN(new_price) AS minPrice, id FROM product_kits GROUP BY id
) AS tmpKits on `tmpKits`.`id` = `product_kits`.`id`
where `category_id` in ('62')
group by `catalog_products`.`id`
order by product_kits.new_price ASC
Result:
And this is incorrect sorting!
Somehow when I group this results, I get id 280 before 281!
But I need to get:
281|1600.00
280|2340.00
So, grouping breaks existing ordering!
For one, when you apply the GROUP BY to only one column, there is no guarantee that the values in the other columns will be consistently correct. Unfortunately, MySQL allows this type of SELECT/GROUPing to happen other products don't. Two, the syntax of using an ORDER BY in a subquery while allowed in MySQL is not allowed in other database products including SQL Server. You should use a solution that will return the proper result each time it is executed.
So the query will be:
For one, when you apply the GROUP BY to only one column, there is no guarantee that the values in the other columns will be consistently correct. Unfortunately, MySQL allows this type of SELECT/GROUPing to happen other products don't. Two, the syntax of using an ORDER BY in a subquery while allowed in MySQL is not allowed in other database products including SQL Server. You should use a solution that will return the proper result each time it is executed.
So the query will be:
select CP.`id`, CP.`alias`, TK.`minPrice`
from catalog_products CP
left join `product_kits` PK on PK.`product_id` = CP.`id`
left join (
SELECT MIN(`new_price`) AS "minPrice", `id` FROM product_kits GROUP BY `id`
) AS TK on TK.`id` = PK.`id`
where CP.`category_id` IN ('62')
order by PK.`new_price` ASC
group by CP.`id`
The thing is that group by does not recognize order by in MySQL.
Actually, what I was doing is really bad practice.
In this case you should use distinct and by catalog_products.*
In my opinion, group by is really useful when you need group result of agregated functions.
Otherwise you should not use it to get unique values.
I'm building a MySQL query with subqueries. The query requires, as described in Getting the number of rows with a GROUP BY query, the number of records returned by a group-by query, because I want the number of days with records in the database. So I'm using the following:
SELECT
COUNT(*)
FROM
(
SELECT
cvdbs2.dateDone
FROM
cvdbStatistics cvdbs2
WHERE
cvdbs2.mediatorId = 123
GROUP BY
DATE_FORMAT( cvdbs2.dateDone, "%Y-%d-%m" )
) AS activityTempTable
Now, I want this as a subquery, because I need some more data with different WHERE statements. So my query becomes:
SELECT
x,
y,
z,
(
SELECT
COUNT(*)
FROM
(
SELECT
cvdbs2.dateDone
FROM
cvdbStatistics cvdbs2
WHERE
cvdbs2.mediatorId = mediators.id
GROUP BY
DATE_FORMAT( cvdbs2.dateDone, "%Y-%d-%m" )
) AS activityTempTable
) AS activeDays
FROM
mediators
LEFT JOIN
cvdbStatistics
ON
mediators.id = cvdbStatistics.mediatorId
WHERE
mediators.recruiterId = 409
GROUP BY
mediators.email
(I left out some irrelevant WHERE-statements from my queries. 409 is just an example id, this is inserted by PHP).
Now, I'm getting the following error:
#1054 - Unknown column 'mediators.id' in 'where clause'
MySQL forgot about the mediators.id in the deepest subquery. How can I build a query, with the number of results of a GROUP-BY query, which requires a value from the main query, as one of the results? Why isn't the deepest query aware of 'mediators.id'?
Try the following:
SELECT
x,
y,
z,
(
SELECT
COUNT(distinct DATE_FORMAT( cvdbs2.dateDone, "%Y-%d-%m" ))
FROM
cvdbStatistics cvdbs2
WHERE
cvdbs2.mediatorId = mediators.id
) AS activeDays
FROM
mediators
LEFT JOIN
cvdbStatistics
ON
mediators.id = cvdbStatistics.mediatorId
WHERE
mediators.recruiterId = 409
GROUP BY
mediators.email
Did you try to put also the "mediators" table in the FROM of the deepest subquery ? Because they are two different queries and the tables of the first one are not called in the subquery. I'm not sure of what i say but i think the only relation between the query and the subquery is the result return by the subquery.