I have a table student with a column dte_date (date) having values (2019-01-01,2019-02-01,2019-03-01..etc)
Conditions:
No repeated values in the column dte_date.
But there is a chance of missing values in dte_date(example miss 2019-02-01).
The day of the date field should be 01.
I want a query to check whether any month date is missing from this table.
You can use aggregating and having:
select student_id
from t
group by student_id
having max(dte_date) <> min(dte_date) + interval count(*) - 1 month;
Note that this assumes that you don't have duplicates in the table -- although that could be handled with count(distinct).
Related
I have a date/time field in my table called startTime.
I would like the output as follows:
select
YEAR(startTime),
MONTH(startTime),
DAY(startTime),
dayofmonth(startTime),
startTime,
...
This is fine, and I only have to group by startTime.
However, for my output, I am only really interested in the date part of the startTime.
So I changed my output to be
select
YEAR(startTime),
MONTH(startTime),
DAY(startTime),
dayofmonth(startTime),
DATE(startTime),
...
When I try to run this, SQL makes me group by Year, Month, day, dayofmonth and date(startTime).
This seems to be a quirk of the date() function?
I thought maybe it's due to the time part of the startTime field, but Year, Month, Day and dayofmonth are no more granular than a date so I am confused as why I have to group by those.
Any insights greatly appreciated!
My code currently:
YEAR(startTime),
MONTH(startTime),
DAY(startTime),
dayofmonth(startTime),
date(startTime),
count(id)
from
bookings
group by 1, 2, 3, 4, 5
in your select statement we must have distinct values of selected column (as a group) for every distinct value given value of what we group them by.
For example if you have startime in your select clause, and also in group by clause, we get distinct values of selected attributes - date, month, year, & startTime for every unique value of starttime. But if you remove starttime from select clause, the attributes selected are no longer guaranteed to be unique.
Consider 2 startTime values 2020-03-12T01:01:01.000UTC and 2020-03-12T02:02:02.000UTC its expected to produce two rows if we group by startTime (as two distinct startTimes), but the selected values for year, month and date would be same in both of these rows (as they differ only in time part) which is breaking the group by contract.
Hence we can only have group of attributes in select clause which MUST provide a different value for every combination of attributes in the group by clause.
I have a MySQL DB where one column is the DATE and the other column is the SIGNAL. Now I would like to calculate the SUM over Signal for 4 days each.
f.e.
SUM(signal over DATE1,DATE2,DATE3,DATE4)
SUM(signal over DATE5,DATE6,DATE7,DATE8)
...
whereas Date_N = successor of DATE_N-1 but need not to be the day before
Moreless the algo should be variable in the days group. 4 ist just an example.
Can anyone here give me an advice how to perform this in MySQL?
I have found this here group by with count, maybe this could be helpful for my issue?
Thanks
Edit: One important note: My date ranges have gaps in it. you see this in the picture below, in the column count(DISTINCT(TradeDate)). It should be always 4 when I have no gaps. But I DO have gaps. But when I sort the date descending, I would like to group the dates together always 4 days, f.e. Group1: 2017-08-22 + 2017-08-21 + 2017-08-20 + 2017-08-19, Group2: 2017-08-18 + 2017-08-17+2017-08-15+2017-08-14, ...
maybe I could map the decending dateranges into a decending integer autoincrement number, then I would have a number without gaps. number1="2017-08-17" number2="2017-08-15" and so on ..
Edit2:
As I see the result from my table with this Query: I might I have double entries for one and the same date. How Can I distinct this date-doubles into only one reprensentative?
SELECT SUM(CondN1),count(id),count(DISTINCT(TradeDate)),min(TradeDate),max(TradeDate) ,min(TO_DAYS(DATE(TradeDate))),id FROM marketstat where Stockplace like '%' GROUP BY TO_DAYS(DATE(TradeDate)) DIV 4 order by TO_DAYS(DATE(TradeDate))
SUM() is a grouping function, so you need to GROUP BY something. That something should change only every four days. Let's start by grouping by one day:
SELECT SUM(signal)
FROM tableName
GROUP BY date
date should really be of type DATE, like you mentioned, not DATETIME or anything else. You could use DATE(date) to convert other date types to dates. Now we need to group by four dates:
SELECT SUM(signal)
FROM tableName
GROUP BY TO_DAYS(date) DIV 4
Note that this will create an arbitary group of four days, if you want control over that you can add a term like this:
SELECT SUM(signal)
FROM tableName
GROUP BY (TO_DAYS(date)+2) DIV 4
In the meantime and with help of KIKO I have found the solution:
I make a temp table with
CREATE TEMPORARY TABLE if not EXISTS tradedatemaptmp (id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY) SELECT Tradedate AS Tradedate, CondN1, CondN2 FROM marketstat WHERE marketstat.Stockplace like 'US' GROUP BY TradeDate ORDER BY TradeDate asc;
and use instead the originate tradedate the now created id in the temp table. So I could manage that - even when I have gaps in the tradedate range, the id in the tmp table has no gaps. And with this I can DIV 4 and get the always the corresponding 4 dates together.
I have a list of date ranges and I like to get a list of all months that are within these date ranges. I can query my date ranges like so:
Select id, start, end
From date_range
And this query would give the following output:
1, 01-01-2016, 25-03-2016
2, 26-03-2016, 30-03-2016
3, 30-12-2016, 08-01-2017
Now I would like to find a MySQL query that just lists all months within these date ranges. So it should give the following output:
01-2016
02-2016
03-2016
12-2016
01-2017
There are already examples here on how to get a list of month between two dates, such as:
Creating a list of month names between two dates in MySQL
How to get a list of months between two dates in mysql
But these examples are about a single date range, but I have multiple date ranges. It would be great if someone can find an sql query for my problem.
Here is a solution:
#DROP TABLE IF EXISTS monthTest;
CREATE TABLE monthTest(id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `start` DATETIME, `end`DATETIME);
INSERT INTO monthTest(`start`, `end`) VALUES
('2016-01-01', '2016-03-25'),
('2016-03-26', '2016-03-30'),
('2016-12-30', '2017-08-01');
SELECT A.`start`, A.`end`, DATE_FORMAT(DATE_ADD(A.`start`, INTERVAL B.help_keyword_id MONTH), '%Y%m') FROM
monthTest A,
mysql.help_keyword B
WHERE PERIOD_DIFF(DATE_FORMAT(A.`end`, '%Y%m'), DATE_FORMAT(A.`start`, '%Y%m')) >= B.help_keyword_id
ORDER BY A.id;
Note that this query in the second JOIN table has a dependency that this table must contain more rows than the maximum number of months between any two dates and the join field must be an incrementing INTEGER starting from 0. This is due to the limitation that mysql doesn't (yet) contain a row generator so a workaround is necessary.
Regards,
James
I have a table - accounts, and it has 3 columns: id , timestamp and value.
I need to create a query that returns a table which in each row it will be the month (2, 3, etc.) and the sum of the values from this month.
for example: if my table will have 3 rows from January and one row from February, the query will return a two-rows table within the first row it'll be 1 and the sum of January's values, and the second will be 2 and the sum of February's values.
I have no idea how to begin. can anyone help me?
all you need to do is sum the value and also use mysql's MONTH() function to pull out the month from your timestamp
SELECT SUM(value) as total_amount, MONTH(timestamp) as month_num
FROM table
GROUP BY month_num
GROUP BY is used when you have an aggregate function (in our case its SUM) to know how to group your common fields. without a group by you will have all rows summed together
SQL Server can use the DATEPART function.
SELECT DATEPART(MONTH, your_date_column) AS month_
, SUM(your_value) AS value_
FROM your_table
GROUP BY DATEPART(MONTH, your_date_column)
So lets say I have some records that look like:
2011-01-01 Cat
2011-01-02 Dog
2011-01-04 Horse
2011-01-06 Lion
How can I construct a query that will return 2011-01-03 and 2011-01-05, ie the unused dates. I postdate blogs into the future and I want a query that will show me the days I don't have anything posted yet. It would look from the current date to 2 weeks into the future.
Update:
I am not too excited about building a permanent table of dates. After thinking about it though it seems like the solution might be to make a small stored procedure that creates a temp table. Something like:
CREATE PROCEDURE MISSING_DATES()
BEGIN
CREATE TABLE TEMPORARY DATES (FUTURE DATETIME NULL)
INSERT INTO DATES (FUTURE) VALUES (CURDATE())
INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 1 DAY))
...
INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 14 DAY))
SELECT FUTURE FROM DATES WHERE FUTURE NOT IN (SELECT POSTDATE FROM POSTS)
DROP TABLE TEMPORARY DATES
END
I guess it just isn't possible to select the absence of data.
You're right — SQL does not make it easy to identify missing data. The usual technique is to join your sequence (with gaps) against a complete sequence, and select those elements in the latter sequence without a corresponding partner in your data.
So, #BenHoffstein's suggestion to maintain a permanent date table is a good one.
Short of that, you can dynamically create that date range with an integers table. Assuming the integers table has a column i with numbers at least 0 – 13, and that your table has its date column named datestamp:
SELECT candidate_date AS missing
FROM (SELECT CURRENT_DATE + INTERVAL i DAY AS candidate_date
FROM integers
WHERE i < 14) AS next_two_weeks
LEFT JOIN my_table ON candidate_date = datestamp
WHERE datestamp is NULL;
One solution would be to create a separate table with one column to hold all dates from now until eternity (or whenever you expect to stop blogging). For example:
CREATE TABLE Dates (dt DATE);
INSERT INTO Dates VALUES ('2011-01-01');
INSERT INTO Dates VALUES ('2011-01-02');
...etc...
INSERT INTO Dates VALUES ('2099-12-31');
Once this reference table is set up, you can simply outer join to determine the unused dates like so:
SELECT d.dt
FROM Dates d LEFT JOIN Blogs b ON d.dt = b.dt
WHERE b.dt IS NULL
If you want to limit the search to two weeks in the future, you could add this to the WHERE clause:
AND d.dt BETWEEN NOW() AND ADDDATE(NOW(), INTERVAL 14 DAY)
The way to extract rows from the mysql database is via SELECT. Thus you cannot select rows that do not exist.
What I would do is fill my blog table with all possible dates (for a year, then repeat the process)
create table blog (
thedate date not null,
thetext text null,
primary key (thedate));
doing a loop to create all dates entries for 2011 (using a program, eg $mydate is the date you want to insert)
insert IGNORE into blog (thedate,thetext) values ($mydate, null);
(the IGNORE keyword to not create an error (thedate is a primary key) if thedate exists already).
Then you insert the values normally
insert into blog (thedate,thetext) values ($mydate, "newtext")
on duplicate key update thetext="newtext";
Finally to select empty entries, you just have to
select thedate from blog where thetext is null;
You probably not going to like this:
select '2011-01-03', count(*) from TABLE where postdate='2011-01-03'
having count(*)=0 union
select '2011-01-04', count(*) from TABLE where postdate='2011-01-04'
having count(*)=0 union
select '2011-01-05', count(*) from TABLE where postdate='2011-01-05'
having count(*)=0 union
... repeat for 2 weeks
OR
create a table with all days in 2011, then do a left join, like
select a.days_2011
from all_days_2011
left join TABLE on a.days_2011=TABLE.postdate
where a.days_2011 between date(now()) and date(date_add(now(), interval 2 week))
and TABLE.postdate is null;