Select how many rows up to a date - mysql

having a list of people like:
name date_of_birth
john 1987-09-08
maria 1987-09-08
samuel 1987-09-09
claire 1987-09-10
jane 1987-09-10
rose 1987-09-12
...
How can I get a result view using SQL of how many people are born up to that date, like the output for that table should be:
date count
1987-09-08 2
1987-09-09 3
1987-09-10 5
1987-09-11 5
1987-09-12 6
...
Thanks!

Here is another way, in addition to Gordon's answer. It uses joins:
SELECT
t1.date_of_birth,
COUNT(*) AS count
FROM (SELECT DISTINCT date_of_birth FROM yourTable) t1
INNER JOIN yourTable t2
ON t1.date_of_birth >= t2.date_of_birth
GROUP BY
t1.date_of_birth;
Note: I left out a step. Apparently you also want to report missing dates. If so, then you may replace what I aliased as t1 with a calendar table. For the sake of demonstration, you can inline all the dates:
SELECT
t1.date_of_birth,
COUNT(*) AS count
FROM
(
SELECT '1987-09-08' AS date_of_birth UNION ALL
SELECT '1987-09-09' UNION ALL
SELECT '1987-09-10' UNION ALL
SELECT '1987-09-11' UNION ALL
SELECT '1987-09-12'
) t1
LEFT JOIN yourTable t2
ON t1.date_of_birth >= t2.date_of_birth
GROUP BY
t1.date_of_birth;
Demo
In practice, your calendar table would be a bona fide table which just contains all the dates you want to appear in your result set.

One method is a correlated subquery:
select dob.date_of_birth,
(select count(*) from t where t.date_of_birth <= dob.date_of_birth) as running_count
from (select distinct date_of_birth from t) dob;
This is not particularly efficient. If your data has any size, variables are better (or window functions if you are using MySQL 8.0):
select date_of_birth,
(#x := #x + cnt) as running_count
from (select date_of_birth, count(*) as cnt
from t
group by date_of_birth
order by date_of_birth
) dob cross join
(select #x := 0) params;

Use subquery with correlation approach :
select date_of_birth, (select count(*)
from table
where date_of_birth <= t.date_of_birth
) as count
from table t
group by date_of_birth;

Related

Is it possible to output the result of a union of two subqueries in alternating order?

Lets say I have two subqueries in a UNION statement like so:
(
SELECT *
FROM users
ORDER BY registration_date
)
UNION ALL
(
SELECT *
FROM food
ORDER BY popularity
)
The output is the following:
Bob
Alice
Steve
Mark
...
Sandwich
Pizza
Burger
Fries
...
Is it possible to output them in an alternating fashion, such that the output is:
Bob
Sandwich
Alice
Pizza
Steve
Burger
Mark
Fries
...
Each query output is thousands of items.
You could use row_number() if you are running MySQL 8.0:
(select name, 1 src, row_number() over(order by registration_date) rn from users)
union all
(select name, 2, row_number() over(order by popularity) from food)
order by rn, src
In each unioned subquery, we use row_number() to rank the records, and add another column, called src to identify from which table the record comes from.
Then all that is left to do is order by the assigned row_number(), using the additional column to alternate the records.
Note that I modified your query to enumerate the columns being selected in the subqueries; select * is generally not a good practice, especially with union all, which requires both datasets to have the same number of columns (with equivalent datatypes).
Just in case you are not using MySQL 8+, you can still simulate ROW_NUMBER using a correlated count query:
(
SELECT 1 AS idx, name,
(SELECT COUNT(*) FROM users u2 WHERE u2.registration_date < u1.registration_date) rn
FROM users u1
)
UNION ALL
(
SELECT 2, name,
(SELECT COUNT(*) FROM food f2 WHERE f2.popularity < f1.popularity) rn
FROM food f1
)
ORDER BY
rn,
idx;
DECLARE #id INT;
SET #id :=0;
SELECT id,t.* FROM(
SELECT u.*,(#id:=#id+1) AS id
FROM users u
ORDER BY registration_date
)
UNION ALL
(
SELECT f.*,(#id:=#id+2) AS id
FROM food f
ORDER BY popularity
)t
ORDER BY id;

Mysql Join query with count table records with same date

Hello i am having two different table with same field created_date (datetime)
now i want records which counts daywise records with joining table i have done for individual counting as below query :
SELECT DATE(created_date), COUNT(*) FROM table1 GROUP BY DAY(created_date)
SELECT DATE(created_date), COUNT(*) FROM table2 GROUP BY DAY(created_date)
and i am getting results for individuals something like this:
RESULT I NEED :
DATE(created_date) count(table1) count(table2)
2016-12-01 10 3
2016-12-02 1 0
2016-12-05 1 0
2016-11-29 1 0
2016-11-30 4 1
Now i just want to join these result WITH INDIVIDUAL VIEW COUNT ACCORDING TO TABLE can anyone please help me out with this profile....
First take a UNION between your two tables, then use conditional aggregation to determine the counts for each of the two tables. Note that I introduce a field called table_name to keep track of data from each of the two tables.
SELECT t.created_date,
SUM(CASE WHEN t.table_name = 'one' THEN 1 ELSE 0 END) AS count_table_one,
SUM(CASE WHEN t.table_name = 'two' THEN 1 ELSE 0 END) AS count_table_two
FROM
(
SELECT DATE(created_date) AS created_date, 'one' AS table_name
FROM table1
UNION ALL
SELECT DATE(created_date), 'two'
FROM table2
) t
GROUP BY t.created_date
I used DATE consistently everywhere to make the query correct.
Try This:
SELECT created_date, sum(countTable1) countTable1,
sum(countTable2) countTable2
FROM (
SELECT DATE(created_date) created_date, COUNT(*) countTable1, NULL countTable2
FROM table1 GROUP BY DAY(created_date)
UNION ALL
SELECT DATE(created_date) created_date, NULL, COUNT(*) countTable2
FROM table2 GROUP BY DAY(created_date)) t GROUP BY t.created_date
You have a problem in your queries, you are grouping by DAY(date) and showing 'date' so the result will be first date with day(date), yet repeating it to avoid misunderstanding :)
select IFNULL(A.cd, B.cd), A.cnt, B.cnt from
(SELECT DAY(created_date) d, DATE(created_date) cd, COUNT(*) cnt
FROM table1 GROUP BY DAY(created_date)) as A
LEFT JOIN
(SELECT DAY(created_date) d, DATE(created_date) cd , COUNT(*) cnt
FROM table2 GROUP BY DAY(created_date)) B ON B.d = A.d
Its not too hard just use union if no need to allow duplicate row else use union all for all(means allow duplicate as well).
SELECT DATE(created_date), COUNT(*) FROM table1 GROUP BY DAY(created_date)
UNION
SELECT DATE(created_date), COUNT(*) FROM table2 GROUP BY DAY(created_date)
SELECT T.create_date,ISNULL(T.count,0)AS Counttable1,ISNULL(X.count,0)AS Counttable2 FROM(SELECT DATE(created_date) AS create_date,COUNT(*) as count FROM table1 GROUP BY DAY(created_date)) AS T LEFTJOIN(SELECT DATE(created_date) AS create_date, COUNT(*) as count FROM table2 GROUP BY DAY(created_date))AS X ON T.create_date=X.create_date
You actually need a SQL UNION. JOIN natuarually eliminate counts becuase the maytch fields. I.e. if you had 2016-12-01 in both table1 andtable2 then a JOIN on created_date would give you a count of 1 instead of a count of 2.
SELECT DATE(total.created_date), COUNT(*)
FROM (
SELECT created_date FROM table1
UNION ALL
SELECT created_date FROM table2) as total
GROUP BY total.created_date
HERE you simply union the two tables since they have a matching column name. Then you get back every date from both tables. That is in the inner query. The outer query then does the counting.
Hope that makes sense.

Combining tables while changing id - SQL

I'm trying to create a search function in different tables using UNION and what happened is that the id's are duplicating making the search go wrong. How can I merge different tables into one while no id's are in common?
Here is the example
table1
id name desc
1 henry post
2 albert doth
3 jun cloth
table2
id name desc
1 kin revenge
2 pot eve
The result SHOULD be like this
id name desc
1 henry post
2 albert doth
3 jun cloth
4 kin revenge
5 pot eve
Please help me. Thanks.
In most databases, you would add a new id using the ANSI standard row_number() function:
select row_number() over (order by which, id) as newid, name, description
from (select 1 as which, t1.* from table1 t1 union all
select 2 as which, t2.* from table2 t2
) t;
Note that desc is a really bad name for a column, because it is a SQL keyword and usually a reserved word.
EDIT:
MySQL doesn't support this ANSI standard functionality. Instead, use variables:
select (#rn := #rn + 1) as newid, name, description
from (select 1 as which, t1.* from table1 t1 union all
select 2 as which, t2.* from table2 t2
) t cross join
(select #rn := 0) vars
order by which, id;
I've include the order by so the rows remain in the same order that you seem to want them in -- rows from the first table followed by rows from the second table. If you don't care about the order, just drop the order by.
For SQLite, the calculation is much more painful:
with cte as (
select 1 as which, t1.* from table1 t1 union all
select 2 as which, t2.* from table2 t2
)
select (select count(*)
from cte cte2
where cte2.which < cte.which or (ct2.which = cte.which and cte2.id <= cte.id
) as id,
name, description
from cte;
In MySql, you can simulate the row_number() function of Sql Server and Oracle using a mutating variable hack:
set #rownum := 0;
SELECT #rownum:=#rownum+1 AS` row_number`, `name`, `desc`
FROM
(
SELECT `name`, `desc` FROM table1
UNION
SELECT `name`, `desc` FROM table2
) AS x;
SqlFiddle
It looks like you have to Generate Id's so you can make you Union query as Sub select and generate Id's in Outer Query
MySQL does not have any system function like SQL Server’s row_number () to generate the row number for each row. However, it can be generated using the variable in the SELECT statement
SET #row_number:=0;
SELECT #row_number:=#row_number+1 As Id,
NAME,
desc
FROM (SELECT NAME,desc
FROM table1
UNION ALL
SELECT NAME,desc
FROM table2
UNION ALL
........
........) A
Order by NAME -- Change the column in Order by in which order you want to create New ID's

MySQL: check that a set of queries returns the same row count : : but I don't know what the count is

We read values from a set of sensors, occasionally a reading or two is lost for a particular sensor , so now and again I run a query to see if all sensors have the same record count.
GROUP BY sensor_id HAVING COUNT(*) != xxx;
So I run a query once to visually get a value of xxx and then run it again to see if any vary.
But is there any clever way of doing this automatically in a single query?
You could do:
HAVING COUNT(*) != (SELECT MAX(count) FROM (
SELECT COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t)
Or else group again by the count in each group (and ignore the first result):
SELECT count, GROUP_CONCAT(sensor_id) AS sensors
FROM (
SELECT sensor_id, COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t
GROUP BY count
ORDER BY count DESC
LIMIT 1, 18446744073709551615
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
ORDER BY count
Will show a list of the sensor_id along with a count of all the records it has, you can then manually check to see if any vary.
SELECT * FROM (
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
) AS t1
GROUP BY count
Will show all the counts that vary, but the group by will lose information about which sensor_ids have which counts.
---EDIT---
Taken a bit from both mine and eggyal's answer and created this, for the count that is most frequent I call the id default, and then for any values that stand out I have given them separate rows. This way you maintain the readability of a table if you have many results Multi Row, but also have a simple one row column if all counts are the same One Row. If however you are happy with the concocted strings then go with eggyal's answer.
Might be a bit over the top but here goes:
select 'default' as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)=
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5 group by count
union all
select t5.id as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)<>
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5

SQL Server Get Max

I have the following table:
ID Date FirstName Dept
1 1/2/12 James Act
1 2/5/12 Mike IT
2 5/6/12 Joe HR
2 7/6/12 Keith IT
What I need to do that for each ID, I need to get the max date.
I need to show ID, Date, FirstName, Dept for the record for each ID that has the Max Date.
So in this case for ID of 1, I would show 1 2/5/12 Mike IT
How do I do this in SQL Server T-SQL?
I know I need to do group by.
The table name is TblAct
You will use the MAX() function with a GROUP BY
select t1.id, t1.date, t1.fname, t1.dept
from tblAct t1
inner join
(
SELECT Max(Date) maxdate, ID
from TblAct
GROUP BY id
) t2
on t1.id = t2.id
and t1.date = t2.maxdate
See SQL Fiddle with Demo
You can do this with windows/ranking functions:
select ID, Date, FirstName, Dept
from (select t.*,
row_number() over (partition by id order by date desc) as seqnum
from t
) t
where seqnum = 1
This is ordering all the rows for each id by date, in reverse order. It then selects the first of them.
dont use group by :
select * from tblAct t1
where date=(select max(date) from tblAct where t1.id = id)
just enjoy.