How to count records as per all year? - php

I need to count record year wise, I did some query but i am not getting correct result. Below is my query. But that is not working for me. Can anyone please look in this and give me right query ? Any help will be appreciated.
SELECT
(SELECT count(DISTINCT id) FROM call_response WHERE disposition=0 AND user_id=pu.id ) AS `trueAlarm`,
(SELECT count(DISTINCT id) FROM call_response WHERE disposition=1 AND user_id=pu.id ) AS `falseAlarm`,
(SELECT count(DISTINCT id) FROM call_response WHERE disposition=2 AND user_id=pu.id ) AS `disregarded`,
YEAR(cr.created_date) AS `callYear`
FROM `call_response` AS `cr`
INNER JOIN `permit_users` AS `pu`
ON cr.user_id=pu.id
WHERE ( pu.is_deleted=0 AND pu.is_trashed=0 AND cr.is_deleted=0)
GROUP BY `callYear`

The query that you want uses either conditional aggregation or subqueries, but not both. In other words, either use the subqueries but do not have an outer join to call_response. Or, have the outer join but not the subqueries.
I would write the query like this:
SELECT count(distinct case when disposition = 0 AND user_id = pu.id then id end) as trueAlarm,
count(distinct case when disposition = 1 AND user_id = pu.id then id end) as falseAlarm,
count(distinct case when disposition = 2 AND user_id = pu.id then id end) as disregarded,
YEAR(cr.created_date) AS `callYear`
FROM `call_response` `cr` INNER JOIN
`permit_users` `pu`
ON cr.user_id = pu.id
WHERE pu.is_deleted = 0 AND pu.is_trashed = 0 AND cr.is_deleted = 0
GROUP BY `callYear`;

Related

sql calculating query doesn't run, #1054 unknown column in field list

I want to create query that would show is the certain section is passed by certain account_id. It means all lessons of the section is checked = 1(true). I tried this solution:
SELECT count(*) as checked,(
SELECT count(*)
FROM lessons
WHERE section_id = 1
GROUP BY section_id
) as cnt, (checked = cnt) as passed
FROM lessons l
LEFT JOIN progress p ON l.id = p.lesson_id
WHERE l.section_id = 1 AND p.account_id = 3 AND checked = 1
GROUP BY l.section_id
But it returns error:
#1054 unknown 'cnt' column in field list.
What do I do wrong?
The unknown 'cnt' is generated from (checked=cnt) as passed. Try this
SELECT checked, cnt, (checked=cnt) as passed FROM (SELECT count(*) as checked,(
SELECT count(*)
FROM lessons
WHERE section_id = 1
GROUP BY section_id
) as cnt
FROM lessons l
LEFT JOIN progress p ON l.id = p.lesson_id
WHERE l.section_id = 1 AND p.account_id = 3 AND checked = 1
GROUP BY l.section_id) tblA
Note that you should move all conditions on the p.* columns to the ON clause. Otherwise you will convert the LEFT JOIN to an INNER JOIN and COUNT(*) will always be the same as in your subquery. However you don't even need that subquery - You can get the same value with COUNT(p.lesson_id) instead. It will ignore all rows with NULL.
SELECT
COUNT(*) as cnt,
COUNT(p.lesson_id) as checked,
COUNT(*) = COUNT(p.lesson_id) as passed
FROM lessons l
LEFT JOIN progress p
ON p.lesson_id = l.id
AND p.account_id = 3
AND p.checked = 1
WHERE l.section_id = 1
SELECT count(*) as checked, (SELECT count(*) FROM lessons
WHERE section_id = 1 GROUP BY section_id) as cnt,
((SELECT count(*) FROM lessons WHERE section_id = 1 GROUP BY section_id) = checked) pass
FROM lessons l LEFT JOIN progress p ON l.id = p.lesson_id
WHERE l.section_id = 1 AND p.account_id = 3 AND checked = 1 GROUP BY l.section_id
Thanks to #aynber. Though I'm not sure if this solution isn't too bulky.

Get multiple row counts [duplicate]

I am wondering how to write this query.
I know this actual syntax is bogus, but it will help you understand what I want.
I need it in this format, because it is part of a much bigger query.
SELECT distributor_id,
COUNT(*) AS TOTAL,
COUNT(*) WHERE level = 'exec',
COUNT(*) WHERE level = 'personal'
I need this all returned in one query.
Also, it need to be in one row, so the following won't work:
'SELECT distributor_id, COUNT(*)
GROUP BY distributor_id'
You can use a CASE statement with an aggregate function. This is basically the same thing as a PIVOT function in some RDBMS:
SELECT distributor_id,
count(*) AS total,
sum(case when level = 'exec' then 1 else 0 end) AS ExecCount,
sum(case when level = 'personal' then 1 else 0 end) AS PersonalCount
FROM yourtable
GROUP BY distributor_id
One way which works for sure
SELECT a.distributor_id,
(SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
(SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
(SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
FROM (SELECT DISTINCT distributor_id FROM myTable) a ;
EDIT:
See #KevinBalmforth's break down of performance for why you likely don't want to use this method and instead should opt for #Taryn♦'s answer. I'm leaving this so people can understand their options.
SELECT
distributor_id,
COUNT(*) AS TOTAL,
COUNT(IF(level='exec',1,null)),
COUNT(IF(level='personal',1,null))
FROM sometable;
COUNT only counts non null values and the DECODE will return non null value 1 only if your condition is satisfied.
Building on other posted answers.
Both of these will produce the right values:
select distributor_id,
count(*) total,
sum(case when level = 'exec' then 1 else 0 end) ExecCount,
sum(case when level = 'personal' then 1 else 0 end) PersonalCount
from yourtable
group by distributor_id
SELECT a.distributor_id,
(SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
(SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
(SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
FROM myTable a ;
However, the performance is quite different, which will obviously be more relevant as the quantity of data grows.
I found that, assuming no indexes were defined on the table, the query using the SUMs would do a single table scan, while the query with the COUNTs would do multiple table scans.
As an example, run the following script:
IF OBJECT_ID (N't1', N'U') IS NOT NULL
drop table t1
create table t1 (f1 int)
insert into t1 values (1)
insert into t1 values (1)
insert into t1 values (2)
insert into t1 values (2)
insert into t1 values (2)
insert into t1 values (3)
insert into t1 values (3)
insert into t1 values (3)
insert into t1 values (3)
insert into t1 values (4)
insert into t1 values (4)
insert into t1 values (4)
insert into t1 values (4)
insert into t1 values (4)
SELECT SUM(CASE WHEN f1 = 1 THEN 1 else 0 end),
SUM(CASE WHEN f1 = 2 THEN 1 else 0 end),
SUM(CASE WHEN f1 = 3 THEN 1 else 0 end),
SUM(CASE WHEN f1 = 4 THEN 1 else 0 end)
from t1
SELECT
(select COUNT(*) from t1 where f1 = 1),
(select COUNT(*) from t1 where f1 = 2),
(select COUNT(*) from t1 where f1 = 3),
(select COUNT(*) from t1 where f1 = 4)
Highlight the 2 SELECT statements and click on the Display Estimated Execution Plan icon. You will see that the first statement will do one table scan and the second will do 4. Obviously one table scan is better than 4.
Adding a clustered index is also interesting. E.g.
Create clustered index t1f1 on t1(f1);
Update Statistics t1;
The first SELECT above will do a single Clustered Index Scan. The second SELECT will do 4 Clustered Index Seeks, but they are still more expensive than a single Clustered Index Scan. I tried the same thing on a table with 8 million rows and the second SELECT was still a lot more expensive.
For MySQL, this can be shortened to:
SELECT distributor_id,
COUNT(*) total,
SUM(level = 'exec') ExecCount,
SUM(level = 'personal') PersonalCount
FROM yourtable
GROUP BY distributor_id
Well, if you must have it all in one query, you could do a union:
SELECT distributor_id, COUNT() FROM ... UNION
SELECT COUNT() AS EXEC_COUNT FROM ... WHERE level = 'exec' UNION
SELECT COUNT(*) AS PERSONAL_COUNT FROM ... WHERE level = 'personal';
Or, if you can do after processing:
SELECT distributor_id, COUNT(*) FROM ... GROUP BY level;
You will get the count for each level and need to sum them all up to get the total.
I do something like this where I just give each table a string name to identify it in column A, and a count for column. Then I union them all so they stack. The result is pretty in my opinion - not sure how efficient it is compared to other options but it got me what I needed.
select 'table1', count (*) from table1
union select 'table2', count (*) from table2
union select 'table3', count (*) from table3
union select 'table4', count (*) from table4
union select 'table5', count (*) from table5
union select 'table6', count (*) from table6
union select 'table7', count (*) from table7;
Result:
-------------------
| String | Count |
-------------------
| table1 | 123 |
| table2 | 234 |
| table3 | 345 |
| table4 | 456 |
| table5 | 567 |
-------------------
Based on Taryn's response with an added nuance using OVER():
SELECT distributor_id,
COUNT(*) total,
SUM(case when level = 'exec' then 1 else 0 end) OVER() ExecCount,
SUM(case when level = 'personal' then 1 else 0 end) OVER () PersonalCount
FROM yourtable
GROUP BY distributor_id
Using OVER() with nothing in the () will give you the total count for the whole dataset.
I think this can also works for you select count(*) as anc,(select count(*) from Patient where sex='F')as patientF,(select count(*) from Patient where sex='M') as patientM from anc
and also you can select and count related tables like this select count(*) as anc,(select count(*) from Patient where Patient.Id=anc.PatientId)as patientF,(select count(*) from Patient where sex='M') as patientM from anc
In Oracle you'll do something like
SELECT
(SELECT COUNT(*) FROM schema.table1),
(SELECT COUNT(*) FROM schema.table2),
...
(SELECT COUNT(*) FROM schema.tableN)
FROM DUAL;
If your flavor of SQL supports it, you can use COUNT_IF() to count based on a condition.
SELECT
distributor_id,
COUNT(*) AS total_count,
COUNT_IF(level = 'exec') AS exec_count,
COUNT_IF(level = 'personal') AS personal_count
FROM table_name
GROUP BY distributor_id
The recently added PIVOT functionality can do exactly what you need:
SELECT *
FROM ( SELECT level from your_table )
PIVOT ( count(*) for level in ('exec', 'personal') )

Conditional group by in mysql

I had a mysql query where i need to add some condition in Group by statement , if i use single field in Group by it works but i need two field include in the Group by, here is my query any one please help me to find out the issue
SELECT (CASE
WHEN CSR.skill_type = 1 THEN
(SELECT skills_value from cv_skills
WHERE skills_id = CSR.skill_id )
WHEN CSR.skill_type = 2 THEN
(SELECT ostype_name from cv_os_type
WHERE ostype_id = CSR.skill_id )
WHEN CSR.skill_type = 3 THEN
(SELECT dbtype_name from cv_db_type
WHERE dbtype_id = CSR.skill_id)
WHEN CSR.skill_type = 4 THEN
(SELECT title from candidate_competencies
WHERE id = CSR.skill_id)
WHEN CSR.skill_type = 0 THEN
IT.type_name
END) AS skill_name,
(CASE
WHEN IT.type_parent_id > 0 THEN
IT.type_parent_id
WHEN IT.type_parent_id = 0 THEN
CIS.interview_type
END) AS typeId,
(CASE
WHEN CSR.skill_type = 4 THEN
minimum_rating
END) AS minimum_rating,
AVG( CSR.rate ) AS skill_rating,
CSR.skill_type,CIS.created, CC.id
FROM `candidate_interview_skill_rate` `CSR`
LEFT JOIN `candidate_interview_process` `CIP` ON CSR.interview_process_id = CIP.id
LEFT JOIN `candidate_interview_schedule` `CIS` ON CIS.id = CIP.interview_schedules_id AND CIS.archive_date IS NULL
LEFT JOIN `candidate_interview` `CI` ON CI.id = CIS.interview_id AND CI.archived_date IS NULL
LEFT JOIN `interview_type` `IT` ON IT.id = CIS.interview_type
LEFT JOIN `candidate_competencies` `CC` ON CC.id = CSR.skill_id
WHERE CI.candidate_user_id = 39
GROUP BY (CASE
WHEN CSR.skill_type > 0 THEN
CSR.skill_id, CSR.skill_type
ELSE CIS.interview_type
END)
ORDER BY `CSR`.`skill_type`
You can concatenate CSR.skill_id, CSR.skill_type to a single column and use it in select statement. The group by needs to be like this
GROUP BY CASE
WHEN CSR.skill_type > 0 THEN
CONCAT(CSR.skill_id, '-', CSR.skill_type)
ELSE
CIS.interview_type
END;
Hope this works.
You can include multiple expressions in a GROUP BY clause, just separate the expressions with commas, just like in the SELECT list.
Very often, the expressions in the SELECT list are repeated in the GROUP BY clause.
It's often possible to use a CASE expression to support a more complex set of conditions.
It's hard to provide more concrete assistance with your query, absent sample data, and desired output.

Mysql in conditon related query

SELECT ac1.id, ac1.course_name, case when a.yettoapprove is not null
then 'true'
else 'false'
end OrderedAll , a.* from (SELECT ac.id, sum(case when ad.status = '2' then 1 else 0 end) as yettoapprove , sum(case when ad.status = '1' then 1 else 0 end) as approved,case when ad.status = '2' is not null
then 'true'
else 'false'
end OrderedAll FROM aw_ou_student_data ad , jos_users ju , aw_ou_lookup_courses ac,aw_ou_lookup_colleges ac1 where ac1.id=ju.college_code and ac.id in (27,28,29,30,133,32,33,34,35,36,37,38,39,40,41,42,43,44,134,135) and ac.school_id=2 and ju.id=ad.user_id and ac.id=ju.course_code GROUP BY ac.id ORDER BY ac.id ) a left join aw_ou_lookup_courses ac1 on ac1.id = a.id
In the above inner query in above one i have given 20 ac.id but i am getting only 14 out records as a result. How do i get the total 20 records as a result. i.e The id present in the in condition if it doesnt satisfy then i should a record with 0 as values for it beside that id.
How do i do it..?
A simple left join with condition should do it:
SELECT
table1.id,
table2.*
FROM
table table1
LEFT JOIN table2 ON table1.id = table2.id AND (your conditions here)

Limiting a left join to returning one result?

I currently have this left join as part of a query:
LEFT JOIN movies t3 ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The trouble is that if there are several movies with the same name and same popularity (don't ask, it just is that way :-) ) then duplicate results are returned.
All that to say, I would like to limit the result of the left join to one.
I tried this:
LEFT JOIN
(SELECT t3.movie_name FROM movies t3 WHERE t3.popularity = 0 LIMIT 1)
ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The second query dies with the error:
Every derived table must have its own alias
I know what I'm asking is slightly vague since I'm not providing the full query, but is what I'm asking generally possible?
The error is clear -- you just need to create an alias for the subquery following its closing ) and use it in your ON clause since every table, derived or real, must have its own identifier. Then, you'll need to include movie_id in the subquery's select list to be able to join on it. Since the subquery already includes WHERE popularity = 0, you don't need to include it in the join's ON clause.
LEFT JOIN (
SELECT
movie_id,
movie_name
FROM movies
WHERE popularity = 0
ORDER BY movie_name
LIMIT 1
) the_alias ON t1.movie_id = the_alias.movie_id
If you are using one of these columns in the outer SELECT, reference it via the_alias.movie_name for example.
Update after understanding the requirement better:
To get one per group to join against, you can use an aggregate MAX() or MIN() on the movie_id and group it in the subquery. No subquery LIMIT is then necessary -- you'll receive the first movie_id per name withMIN() or the last with MAX().
LEFT JOIN (
SELECT
movie_name,
MIN(movie_id) AS movie_id
FROM movies
WHERE popularity = 0
GROUP BY movie_name
) the_alias ON t1.movie_id = the_alias.movie_id
LEFT JOIN movies as m ON m.id = (
SELECT id FROM movies mm WHERE mm.movie_id = t1.movie_id
ORDER BY mm.id DESC
LIMIT 1
)
you could try to add GROUP BY t3.movie_id to the first query
Try this:
LEFT JOIN
(
SELECT t3.movie_name, t3.popularity
FROM movies t3 WHERE t3.popularity = 0 LIMIT 1
) XX
ON t1.movie_id = XX.movie_id AND XX.popularity = 0
On MySQL 5.7+ use ANY_VALUE & GROUP_BY:
SELECT t1.id,t1.movie_name, ANY_VALUE(t3.popularity) popularity
FROM t1
LEFT JOIN t3 ON (t3.movie_id=t1.movie_id AND t3.popularity=0)
GROUP BY t1.id
more info
LEFT JOIN only first row
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Easy solution to left join the 1 most/least recent row is using select over ON phrase
SELECT A.ID, A.Name, B.Content
FROM A
LEFT JOIN B
ON A.id = (SELECT MAX(id) FROM B WHERE id = A.id)
Where A.id is the auto-incremental primary key.
LEFT JOIN (
SELECT id,movie_name FROM movies GROUP BY id
) as m ON (
m.id = x.id
)
// Mysql
SELECT SUM(db.item_sales_nsv) as total FROM app_product_hqsales_otc as db
LEFT JOIN app_item_target_otc as it ON
db.id = (SELECT MAX(id) FROM app_item_target_otc as ot WHERE id = db.id)
and db.head_quarter = it.hqcode
AND db.aaina_item_code = it.aaina_item_code AND db.month = it.month
AND db.year = it.year
WHERE db.head_quarter = 'WIN001' AND db.month = '5' AND db.year = '2022' AND db.status = '1'

Categories