COUNT evaluate to zero if no matching records - ms-access

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
;

Related

MySQL - How to get one of the repeated records given a condition in SQL?

I have the next results from a query. I did this:
Where the user "Adriana Smith" with ID 6 is repeated because she has different contract dates, to do that I did a left join from table bo_users to bo_users_contracts (1:m One to Many Relation). The query is below:
SELECT bo_users.ID, bo_users.display_name, COALESCE (bo_users_contracts.contract_start_date,'-') AS contract_start_date, COALESCE (bo_users_contracts.contract_end_date, '-') AS contract_end_date, COALESCE (bo_users_contracts.current,'-') AS current
FROM bo_users
LEFT JOIN bo_users_contracts ON bo_users.ID = bo_users_contracts.bo_users_id
LEFT JOIN bo_usermeta ON bo_users.ID = bo_usermeta.user_id
WHERE (bo_usermeta.meta_key = 'role' AND bo_usermeta.meta_value = 'member')
But I want to get all users, but from user Adriana I just want to get the occurrence where "current" column = 1.
So the final result would be the 3 user's records:
Alejandro, Rhonda and Adriana (with "current" = 1)
Thank you!
Since you want to limit on a table being outer joined, the limit should be placed on the join itself so the all records from bo_users is retained. (as indicated desired by the outer join)
Essentially the limit is applied before the join so the unmatched records from BO_users to bo_users_contracts are kept. If applied after the join in a where clause the records from BO_user without a matching record would have a null value for current and thus be excluded when the current=1 filter is applied.
In this example the only values which should be in the where would be from table BO_USERS.
I'd even move the bo_usermeta filters to the join or you may lose bo_users; or the left join on the 3rd table should be an inner join.
SELECT bo_users.ID
, bo_users.display_name
, COALESCE (bo_users_contracts.contract_start_date,'-') AS contract_start_date
, COALESCE (bo_users_contracts.contract_end_date, '-') AS contract_end_date
, COALESCE (bo_users_contracts.current,'-') AS current
FROM bo_users
LEFT JOIN bo_users_contracts
ON bo_users.ID = bo_users_contracts.bo_users_id
and bo_users_contracts.current = 1
LEFT JOIN bo_usermeta --This is suspect
ON bo_users.ID = bo_usermeta.user_id
WHERE (bo_usermeta.meta_key = 'role' --this is suspect
AND bo_usermeta.meta_value = 'member') --this is suspect
The lines reading this is suspect are that way because you have a left join which means you want all users from bo_users.. However if a user doesn't have a meta_key or meta_value defined, they would be eliminated. Either change the join to an inner join or move the where clause limits to the join. I indicate this as you're query is "inconsistent" in it's definition leading to ambiguity when later maintained.

JOIN on multiple tables giving duplicate records - MySql

Here is list of my tables and necessary columns
users u .
screen_name,
country,
status
twitter_users_relationship tf. This table have multiple target_screen_name for each screen_name.
screen_name,
target_screen_name,
target_country,
follow_status
user_twitter_action_map ta
screen_name,
action_name,
action_status
user_targeted_countries utc .This table have multiple countries for each screen_name
screen_name,
country_name
I want to get all target_screen_name from twitter_users_relationship that have matched target_country with u.country or utc.country_name
My query so far
SELECT u.screen_name,
u.country,
tf.target_screen_name,
tf.target_country,
ta.action_name,
ta.action_status,
utc.country_name
FROM users u
LEFT JOIN twitter_users_relationship tf
ON u.screen_name=tf.screen_name
LEFT JOIN user_twitter_action_map ta
ON u.screen_name=ta.screen_name
AND ta.action_name='follow'
AND ta.action_status='active'
LEFT JOIN user_targeted_countries utc
ON u.screen_name= utc.screen_name
WHERE u.status = 'active'
AND tf.follow_status = 'pending'
AND tf.target_country != ''
AND tf.target_country IS NOT NULL
AND ( utc.country_name=tf.target_country OR u.country=tf.target_country)
AND u.screen_name = 'my_screen_name';
But this query giving me duplicate record for each entry of countries in user_targeted_countries. If there are 3 counties in user_targeted_countries the it will return 3 duplicate records.
Please let me know what JOIN I need to use with user_targeted_countries to get desired results.
u.country can be different than countries in utc.country_name
UPDATE -
If I removes OR u.country=tf.target_country from the WHERE clause then I get all the matched target_screen_name without duplicate. But I am not sure how to get all those records also that matches with u.country=tf.target_country ?
Depends on the business logic required ..
First, regardless to the question, your query is wrong(Either the LEFT JOIN or the conditions) . When using LEFT JOIN , conditions on the right table should only be specified in the ON clause, which means you need to move all the conditions on tf. and utc. to the ON clause.
Secondly, you can use a GROUP BY clause and choose one of the utc.country_name (different answers will be if you want a specific one, if it doesn't matter, use MAX() on this column).

INNER JOIN selects only one row from second table

I would like to get last value of the second table using mysql inner join.
This is my first table name 'tb_reg'
Second table 'tb_stud_qulification'
I want to get the last date of the 'candidate_no' where first table 'id' equqal to the second table 'candidate_no'.
I wrote inner join code like this but i'm getting error
SELECT reg.*, quli.course, quli.total_per
FROM tb_reg AS reg
INNER JOIN tb_stud_qulification AS quli ON reg.stage = '2' AND reg.id = quli.candidate_no AND
ORDER BY quli.id
LIMIT 1
I would like to get the result like this
you can show:
`http://stackoverflow.com/questions/8821920/sql-sqlite-select-with-inner-join`
example:
SELECT doctors.doctor_id,doctors.doctor_name,visits.patient_name
FROM doctors
INNER JOIN visits
ON doctors.doctor_id=visits.doctor_id
WHERE doctors.degree='MD';
I would write it like this (watch the different ON and WHERE clauses)
SELECT reg.*, quli.course, quli.total_per
FROM tb_reg AS reg
INNER JOIN tb_stud_qulification AS quli ON reg.id = quli.candidate_no
WHERE reg.stage = '2'
ORDER BY quli.id
LIMIT 1
but apart from that, I don't see a stage field in your tb_reg table...

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 Query needs to bring back rows, not empty results

OK, I've voted to delete my earlier question due to stupidity on my part...
I have the following code:
SELECT qnum, id, name, total_staff AS StaffCount, COUNT( q61g ) AS TotalResp,
(COUNT( q61g ) / total_staff * 100) AS Perc
FROM tdemog_pfp
LEFT JOIN tresults_pfp ON tdemog_pfp.id = tresults_pfp.q61g
WHERE qnum = 'q61g' AND q60p = '1'
GROUP BY name
ORDER BY name
Now, the first part of this query brings back rows from the tdemog table, for example it will bring back 5 rows of data each row has an id from 1 to 5. What I need the query to do is then bring back data from the tresults table WHERE q60p = 1 for each of the 5 rows brought back in the first part - like a normal `LEFT JOIN'.
Make sense?
H.
Try moving part of your WHERE clause into your JOIN condition:
SELECT ...
FROM tdemog_pfp
LEFT JOIN tresults_pfp ON tdemog_pfp.id = tresults_pfp.q61g AND q60p = '1'
WHERE qnum = 'q61g'
GROUP BY name
ORDER BY name
If you have a field from your second table in your WHERE clause, it will restrict the entire record... but if you put it into your JOIN condition, the record from the first table should still be returned even when the record in the second table doesn't meet the additional criteria...
I'm not sure which column belongs to which table... but move whatever columns are in your second table into your JOIN.