How to get sum of a UNION ALL - php

How to get sum of all rows in a UNION ALL query. I am trying to get sum a column of every UNION table, And Sum of result after query execution.
$select = $db->prepare("SELECT SUM(money) AS cash FROM table1 WHERE money > 0 GROUP BY id
UNION ALL
SELECT SUM(payment) AS cash FROM table2 WHERE payment > 0 GROUP BY id
UNION ALL
SELECT SUM(pay) AS cash FROM table3 WHERE pay > 0 GROUP BY id
");
$select ->execute();
for($i=0;
$rows = $select ->fetch();
$i++){
$result = $rows['sum(cash)'];

A possible solution with only mysql could be the following, which returns a single value of the summation of all three columns in the tables:
SELECT SUM(pt.psum) AS tsum FROM
(SELECT SUM(money) AS psum FROM table1 WHERE money > 0 GROUP BY id
UNION ALL
SELECT SUM(payment) AS psum FROM table2 WHERE money > 0 GROUP BY id
UNION ALL
SELECT SUM(pay) AS psum FROM table3 WHERE money > 0 GROUP BY id) pt
For clarity,
psum: partial sum
pt: partial sum table
tsum: total sum

Related

how to combine two queries in larvel way

I have 3 tables:
tb_user
tb_addquestion
tb_answer
The following queries return count of questions per user (query 1) and answers per user (query 2). I need to combine the results to a single output.
How can I achieve this with the help of a single query?
Count of questions per user (query1)
SELECT tb_addquestion.userid,
COUNT(*) AS count
FROM tb_addquestion
LEFT JOIN tb_user
ON tb_user.userid = tb_addquestion.userid
GROUP BY tb_addquestion.userid
HAVING count > 0 AND
count < 15
Answers per user (query2)
SELECT tb_answer.userid,
COUNT(*) AS count
FROM tb_answer
LEFT JOIN tb_user
ON tb_user.userid = tb_answer.userid
GROUP BY tb_answer.userid
HAVING count > 0 AND
count < 15
You could use UNION:
SELECT tb_addquestion.userid,
COUNT(*) AS count,
'questions' AS type
FROM tb_addquestion
LEFT JOIN tb_user
ON tb_user.userid = tb_addquestion.userid
GROUP BY tb_addquestion.userid
HAVING count > 0 AND
count < 15
UNION
SELECT tb_answer.userid,
COUNT(*) AS count,
'answers' AS type
FROM tb_answer
LEFT JOIN tb_user
ON tb_user.userid = tb_answer.userid
GROUP BY tb_answer.userid
HAVING count > 0 AND
count < 15
Typically we would perform the aggregations in separate subqueries, and then join the main table to each of those subqueries:
SELECT
u.userid,
COALESCE(aq.q_cnt, 0) AS q_cnt,
COALESCE(a.a_cnt, 0) AS a_cnt
FROM tb_user u
LEFT JOIN
(
SELECT userid, COUNT(*) AS q_cnt
FROM tb_addquestion
GROUP BY userid
HAVING q_cnt > 0 AND q_cnt < 15
) aq
ON aq.userid = u.userid
LEFT JOIN
(
SELECT userid, COUNT(*) AS a_cnt
FROM tb_answer
GROUP BY userid
HAVING a_cnt > 0 AND a_cnt < 15
) a
ON a.userid = u.userid

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') )

How to get count of records which have duplicate value in mysql

I have a table with player and status, this table not got corrupted and it has duplicate entries like this:
player_id status
----------------------
1 100
2 100
2 101
3 100
1 101
2 101
As you can see this record is duplicate: 2,101
How can I find such records using a mysql query?
I tried:
select * from player group by player_id, status having count(status) > 1 but it did not help.
You can SELECT duplicate records as like that:
SELECT COUNT(*) as total,player_id,`status`
FROM `player`
GROUP BY player_id,`status`
HAVING total > 1;
Do it in a outer query like
select * from (
select *, count(*) as rowcount
from player
group by player_id, status ) tab
where rowcount > 1
You can try this query.
$qrys = <<<QUERY
select s.id, t.*
from player s
join (
select player_id, status, count(*) as qty
from player
group by player_id, status
having count(*) > 1
) t on s.player_id = t.player_id and s.status = t.status
QUERY;
If you want to delete duplicate record then use this script
$delres= mysql_query($qrys);
$player_id = 0;
$status = 0;
while ($r= mysql_fetch_array($delres)){
if($player_id == $r['player_id'] && $status == $r['status'])
mysql_query("DELETE FROM player WHERE id=".$r['id']);
$player_id = $r['player_id'];
$status = $r['status'];
}
Try this :
select * from player p
inner join ( select player_id, count(*) as duplicate
from player group by player_id
having count(*) > 1) pp
on p.player_id = pp.player_id
Try This
SELECT *, COUNT(status) AS rows_count FROM player
GROUP BY player_id, status HAVING COUNT(status) > 0
You query is near to it just some changes in it to give you count column for every options Try this modified query.
select *, count(status) as count from player
group by player_id, status having count(status) > 0
It will give this type of response
you can do that by
SELECT distinct player .*
FROM player as tb1
join player as tb2
WHERE tb1.status = tb2.status
and tb1.player_id < tb2.player_id
You can do it simply with GROUP BY like this
SELECT `player_id`, `status`, COUNT(*) as cnt FROM `player`
GROUP BY CONCAT(`player_id`, '_', `status`) HAVING cnt > 1
result would be
player_id status cnt
2 101 2

MySQL: Query design issue

My tables are like this:
Table 1 (students)
Table 2 (results)
I want to select all students from Table 1 students who have 4 results in the results table. I tried this query, but with no success:
SELECT *
FROM students
WHERE gender = 'm'
AND (SELECT COUNT( result ) AS count
FROM results
INNER JOIN students ON results.stuID = students.stuID
WHERE result !=0
) =4
ORDER BY rank ASC
You can rewrite your query by using join and HAVING clause to check the count for each student group ,This can be done without using the subquery which sometimes affects on performance
SELECT s.*,COUNT(*) AS count
FROM students s
INNER JOIN results r ON r.stuID = s.stuID
WHERE r.result !=0
GROUP BY s.stuID
HAVING count =4
ORDER BY s.rank ASC
um, that's a little convoluted.
the where clause should come after the subquery, and the subquery still needs to be JOINed back to the main query.
something like
SELECT * FROM students
INNER JOIN (SELECT COUNT(result),results.stuID as count FROM results WHERE result != 0) as result_count
ON result_count.stuID = students.stuID
WHERE result_count.count =4 AND students.gender = 'm'
ORDER BY rank ASC
You have to use alias for table also -
SELECT *
FROM students as a
WHERE gender = 'm'
AND (SELECT COUNT(result) AS count
FROM results as b
WHERE b.stuID = a.stuID AND
(result!=0 OR result IS NOT NULL OR result!='')
) = 4
ORDER BY rank ASC

Mysql Query- for each date max 3 datas

these is my DB table data,{ i have maintained only one Table}
I need to fetch max 3 data from each start_date,
give me any idea to develop query,,
SELECT a.*
FROM Table1 a
INNER JOIN Table1 b ON a.start_date = b.start_date AND a.event_id <= b.event_id
GROUP BY a.event_id,a.start_date
HAVING COUNT(*) <= 3
ORDER BY a.start_date
I may suggest you this query -
SELECT * FROM (
SELECT t1.*, COUNT(*) pos FROM table t1
LEFT JOIN table t2
ON t2.start_date = t1.start_date AND t2.event_id <= t1.event_id
GROUP BY
t1.start_date AND t1.event_id
) t
WHERE
pos <= 3;
It selects 3 rows with min event_id in a start_date group.

Categories