Sum on null values - mysql

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;

Related

what will be correct MySql query?

I am performing the following query having some syntax error:
SELECT count (tbl_staff.staff_id as staff_number),SELECT count (tbl_client.client_id as client_number),SELECT count (tbl_appointment.appt_id as appt_number),SELECT count (tbl_subscription.subscription_id as subscription_number)
FROM tbl_subscription
LEFT JOIN tbl_staff
ON (
tbl_staff.merchant_id = tbl_subscription.merchant_id)
LEFT JOIN tbl_appointment
ON (
tbl_appointment.merchant_id = tbl_subscription.merchant_id)
LEFT JOIN tbl_client
ON (
tbl_client.merchant_id = tbl_subscription.merchant_id)
WHERE tbl_subscription.subscription_id=1;
I want get the count of staff_id, client_d, appointment_id on particular Subscription_id.
Your select list is close, but has a few mistakes. Namely, you only need a single SELECT in your query (not one per field) and the "as ..." descriptor belongs outside the parenthesis.
So this part of the query
SELECT count (tbl_staff.staff_id as staff_number),
SELECT count (tbl_client.client_id as client_number),
SELECT count (tbl_appointment.appt_id as appt_number),
SELECT count (tbl_subscription.subscription_id as subscription_number)
FROM tbl_subscription
would become
SELECT count (tbl_staff.staff_id) as staff_number,
count (tbl_client.client_id) as client_number,
count (tbl_appointment.appt_id) as appt_number,
count (tbl_subscription.subscription_id) as subscription_number
FROM tbl_subscription

COUNT evaluate to zero if no matching records

Take the following:
SELECT
Count(a.record_id) AS newrecruits
,a.studyrecord_id
FROM
visits AS a
INNER JOIN
(
SELECT
record_id
, MAX(modtime) AS latest
FROM
visits
GROUP BY
record_id
) AS b
ON (a.record_id = b.record_id) AND (a.modtime = b.latest)
WHERE (((a.visit_type_id)=1))
GROUP BY a.studyrecord_id;
I want to amend the COUNT part to display a zero if there are no records since I assume COUNT will evaluate to Null.
I have tried the following but still get no results:
IIF(ISNULL(COUNT(a.record_id)),0,COUNT(a.record_id)) AS newrecruits
Is this an issue because the join is on record_id? I tried changing the INNER to LEFT but also received no results.
Q
How do I get the above to evaluate to zero if there are no records matching the criteria?
Edit:
To give a little detail to the reasoning.
The studies table contains a field called 'original_recruits' based on activity before use of the database.
The visits tables tracks new_recruits (Count of records for each study).
I combine these in another query (original_recruits + new_recruits)- If there have been no new recruits I still need to display the original_recruits so if there are no records I need it to evalulate to zero instead of null so the final sum still works.
It seems like you want to count records by StudyRecords.
If you need a count of zero when you have no records, you need to join to a table named StudyRecords.
Did you have one? Else this is a nonsense to ask for rows when you don't have rows!
Let's suppose the StudyRecords exists, then the query should look like something like this :
SELECT
Count(a.record_id) AS newrecruits -- a.record_id will be null if there is zero count for a studyrecord, else will contain the id
sr.Id
FROM
visits AS a
INNER JOIN
(
SELECT
record_id
, MAX(modtime) AS latest
FROM
visits
GROUP BY
record_id
) AS b
ON (a.record_id = b.record_id) AND (a.modtime = b.latest)
LEFT OUTER JOIN studyrecord sr
ON sr.Id = a.studyrecord_id
WHERE a.visit_type_id = 1
GROUP BY sr.Id
I solved the problem by amending the final query where I display the result of combining the original and new recruits to include the IIF there.
SELECT
a.*
, IIF(IsNull([totalrecruits]),consents,totalrecruits)/a.target AS prog
, IIf(IsNull([totalrecruits]),consents,totalrecruits) AS trecruits
FROM
q_latest_studies AS a
LEFT JOIN q_totalrecruitment AS b
ON a.studyrecord_id=b.studyrecord_id
;

How to fix a count() in a query with a "group by" clause?

I have a function that gets a SQL code and inserts a count field in it and executes the query to return the number of rows in it. The objective is to have a dynamic SQL code and be able to get its record count no matter what code it has, because I use it in a registry filter window and I never know what code may be generated, because the user can add as many filters as he/she wants.
But as I use the group by clause, the result is wrong because it is counting the number of times a main registry appears because of the use on many join connections.
The result of that code above should only one row with a columns with 10 as result, but I get a new table with the first columns with a 2 in the first row and a 1 on the other rows.
If I take off the group by clause I will receive a 11 as a count result, but the first row will be counted twice.
What should I do to get a single row and the correct number?
SELECT
COUNT(*) QUERYRECORDCOUNT, // this line appears only in the Count() function
ARTISTA.*,
CATEGORIA.NOME AS CATEGORIA,
ATIVIDADE.NOME AS ATIVIDADE,
LOCALIDADE.NOME AS CIDADE,
MATRICULA.NUMERO AS MAP
FROM
ARTISTA
LEFT JOIN PERFIL ON PERFIL.REGISTRO = ARTISTA.ARTISTA_ID
LEFT JOIN CATEGORIA ON CATEGORIA.CATEGORIA_ID = PERFIL.CATEGORIA
LEFT JOIN ATIVIDADE ON ATIVIDADE.ATIVIDADE_ID = PERFIL.ATIVIDADE
LEFT JOIN LOCALIDADE ON LOCALIDADE.LOCALIDADE_ID = ARTISTA.LOCAL_ATIV_CIDADE
LEFT JOIN MATRICULA ON MATRICULA.REGISTRO = ARTISTA.ARTISTA_ID
WHERE
((ARTISTA.SIT_PERFIL <> 'NORMAL') AND (ARTISTA.SIT_PERFIL <> 'PRIVADO'))
GROUP BY
ARTISTA.ARTISTA_ID
ORDER BY
ARTISTA.ARTISTA_ID;
This always gives you the number of rows for any query you have:
Select count(*) as rowcount from
(
Paste your query here
) as countquery
Since your are GROUPING BY ARTISTA.ARTISTA_ID, COUNT(*) QUERYRECORDCOUNT will return records count for each ARTISTA.ARTISTA_ID value.
If you want GLOBAL count, then you need to use a nested query:
SELECT COUNT(*) AS QUERYRECORDCOUNT
FROM (SELECT
ARTISTA.*,
CATEGORIA.NOME AS CATEGORIA,
ATIVIDADE.NOME AS ATIVIDADE,
LOCALIDADE.NOME AS CIDADE,
MATRICULA.NUMERO AS MAP
FROM
ARTISTA
LEFT JOIN PERFIL ON PERFIL.REGISTRO = ARTISTA.ARTISTA_ID
LEFT JOIN CATEGORIA ON CATEGORIA.CATEGORIA_ID = PERFIL.CATEGORIA
LEFT JOIN ATIVIDADE ON ATIVIDADE.ATIVIDADE_ID = PERFIL.ATIVIDADE
LEFT JOIN LOCALIDADE ON LOCALIDADE.LOCALIDADE_ID = ARTISTA.LOCAL_ATIV_CIDADE
LEFT JOIN MATRICULA ON MATRICULA.REGISTRO = ARTISTA.ARTISTA_ID
WHERE
((ARTISTA.SIT_PERFIL <> 'NORMAL') AND (ARTISTA.SIT_PERFIL <> 'PRIVADO'))
GROUP BY
ARTISTA.ARTISTA_ID
ORDER BY
ARTISTA.ARTISTA_ID);
In this case, you may not need to select those many columns.
If you need to retrieve the all records count with details, then better to use two separate queries.

Mysql LEFT Join query only returns one row when adding Count() mysql function

I have this mysql query (evolving two tables: Users and Files) that's giving me headaches:
SELECT Users.GUID, Users.Name, Users.CreationDate, Files.Date,
Count(Files.GUID) As FilesCount
FROM Users
LEFT JOIN Files ON Users.GUID = Files.UserGUID
WHERE Users.Group = '1'
When I execute it, it always return 1 row (which is not what I want). But if I remove this:
Count(Files.Date) As FilesCount
It correctly return all the rows that I expect.
I basically need to get the number of files that belongs to a user (along with the user info)
My question is: How can I fix this & make the mysql query return the user basic info along with the files count?
BTW, I'm using CodeIgniter 2 with PHP 5 (although I don't think it matters here...)
The COUNT() aggregate will return only one row in absence of a GROUP BY clause, and MySQL is lenient about the presence or contents of the GROUP BY (your query would have failed with a syntax error in most other RDBMS).
Since you have multiple columns, you ought to join against a subquery to get the count per Files.GUID. Although MySQL will permit you to GROUP BY Users.GUID without the subquery, which is simpler, you may not get the results you expect from Users.Name or Users.CreationDate. This method is more portable:
SELECT
Users.GUID,
Users.Name,
Users.CreationDate,
FileCount
FROM
Users
/* Subquery returns UserGUID and associated file count */
LEFT JOIN (
SELECT UserGUID, COUNT(*) AS FileCount
FROM Files
GROUP BY UserGUID
) fc ON Users.GUID = fc.UserGuid
WHERE Users.Group = 1
You need to group by user, otherwise it collapses all to one row: GROUP BY Users.GUID
This query has subquery which separately calculate the total Count of files for each GUID.
SELECT Users.GUID,
Users.Name,
Users.CreationDate,
Files.Date,
c.FilesCount
FROM Users
LEFT JOIN Files
ON Users.GUID = Files.UserGUID
LEFT JOIN
(
SELECT UserGUID, Count(GUID) As FilesCount
FROM Files
GROUP BY UserGUID
) c on c.UserGUID = Users.GUID
-- WHERE Users.Group = '1'

Query always returns one empty row?

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