Is subquery the solution to this? - mysql

Here's the table structure and some sample data:
pID.....month.....year
27 .....3 .....2008
27 .....12 .....2012
31 .....6 .....2008
99 .....1 .....2006
42 .....1 .....2009
pID is the practiceID and month and year represent the date period they've entered data for. I need to grab the number of practices that have entered data for the first time in Oct 2012, Nov 2012, Dec 2012 and so on.
I tried the following query for Oct 2012:
SELECT *
FROM
IPIPKDIS
where
practiceID NOT IN (
SELECT practiceID
from
IPIPKDIS
where
year < 2012 and month < 10
)
and year = 2012
and month = 10
and measureCatRecID = 2
ORDER BY year, month;
but it's grabbing months and year less than 10/2012.
If I run the queries isolated (not as subquery) they both work fine.
Any ideas?

This summary query will yield the first (smallest) date in the table for each value of practiceID.
SELECT practiceID,
MIN(STR_TO_DATE( CONCAT(year, ' ', month), '%Y %m')) first_date
FROM IPIPKDIS
GROUP BY practiceID
If you want to retrieve then the whole row for the first reported month, you'd do a nested query like this:
SELECT *
FROM IPIPKDIS I
JOIN (
SELECT practiceID,
MIN(STR_TO_DATE( CONCAT(year, ' ', month), '%Y %m')) first_date
FROM IPIPKDIS
GROUP BY practiceID
) first ON ( first.practiceID = I.practiceID
AND STR_TO_DATE( CONCAT(I.year, ' ', I.month), '%Y %m') = first.first_date)
The trick to the second query is to use the JOIN to extract just the first-month rows from your table. We use date arithmetic to do the date comparisons.

Related

Query to get records from quarter before current quarter in MySQL

I am trying to get records from quarter before current quarter in MySQL. But not able to figure out how the query will be constructed.
My MySQL table:
Here's my query to get records of current quarter (Jan 2020 to March 2020):
SELECT * FROM `customers` WHERE QUARTER(`customer_date`) = QUARTER(CURRENT_DATE)
AND YEAR(`customer_date`) = YEAR(CURRENT_DATE)
ORDER BY `customer_date` DESC
But when I am using following query to get records from quarter before current quarter i.e. records from Oct 2019 to Dec 2019, the query doesn't yield me correct result. Actually it fetches records of every quarter (Oct to Dec) of all previous years in the table:
SELECT * FROM `customers` WHERE QUARTER(`customer_date`) = QUARTER(CURRENT_DATE - INTERVAL 1 QUARTER)
ORDER BY `customer_date` DESC
I can't use YEAR in above query. If I use the year then query will fail when it will be run in the future e.g. in the quarter of Apr 2020 to Jun 2020.
How can this query be modified to get required result?
Try this will do:
select
*
from
customers
where
quarter(`customer_date`) = quarter(current_date - interval 1 quarter)
and year(customer_date) =
(case
when quarter(curdate()) > 1 then year(current_date)
else year(current_date)-1
end)
order by
`customer_date` desc
db<>fiddle

How to update Query to calc SUM or COUNT using two dates and BETWEEN?

My current query is as such:
SELECT
CAST(COUNT(`MID`) AS UNSIGNED) AS Y,
CONCAT(
LEFT(MONTHNAME(`date`),
3),
' ',
YEAR(`date`)
) AS label
FROM
`reservations`
WHERE
`MID` = 22 AND YEAR(`date`) = YEAR(CURDATE())
GROUP BY
CONCAT(
LEFT(MONTHNAME(DATE),
3),
' ',
YEAR(`date`)
),
YEAR(DATE),
MONTH(DATE)
ORDER BY
YEAR(`date`),
MONTH(`date`) ASC
It produces the following results that we use in Google Charts to show the number of reservations per month.
The issue is we are only getting the number of times a reservation is created, not the number of days between the start date (date) and the end date (dateLast).
Y label
________________
22 Feb 2019
28 Mar 2019
15 Apr 2019
3 May 2019
5 Jun 2019
2 Jul 2019
1 Aug 2019
1 Oct 2019
2 Nov 2019
9 Dec 2019
I've been trying the following update but getting an error related to the BETWEEN operator:
SELECT
CAST(COUNT(`mid`) AS UNSIGNED BETWEEN `date` AND `dateLast`) AS D, CONCAT(
LEFT(MONTHNAME(DATE),
3), ' ', YEAR(DATE) ),
CAST(COUNT(`mid`) AS UNSIGNED) AS Y,
CONCAT(
LEFT(MONTHNAME(DATE),
3),
' ',
YEAR(DATE)
) AS label
FROM
`reservations`
WHERE
`mid` = 22 AND YEAR(DATE) = YEAR(CURDATE())
GROUP BY
CONCAT(
LEFT(MONTHNAME(DATE),
3),
' ',
YEAR(DATE)
),
YEAR(DATE),
MONTH(DATE)
ORDER BY
YEAR(DATE),
MONTH(DATE) ASC
MySQL said: Documentation
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'BETWEEN date AND dateLast) AS D, CONCAT(LEFT(MONTHNAME(DATE),' at line 2
The goal is to get a SUM for all days reserved between AND including date to dateLast Note: dateLast is not counted as it is the Checkout date. Maybe this is too complex for a SQL query and should be handled in PHP as a series of sub-routines?
If you don't need to split the number of days of one reservation over multiple months, then you can just use SUM(DATEDIFF(dateLast, date))
select year(date) y, month(date) m, sum(datediff(dateLast, date)) c
from reservations
group by y, m
order by y, m
db-fiddle
If you want to split them, then I hope your version (MySQL 8+ or MariaDB 10.2+) supports recursive queries. In that case you can expand the date range to one row per day in the range and count them:
with recursive rcte as (
select date, dateLast
from reservations
where dateLast > date -- optional
union all
select rcte.date + interval 1 day, rcte.dateLast
from rcte
where rcte.date < rcte.dateLast - interval 1 day
)
select year(date) y, month(date) m, count(*) c
from rcte
group by y,m
order by y,m
db-fiddle
SQL can definitely handle this. Use the DATEDIFF function
https://www.w3schools.com/sql/func_mysql_datediff.asp

mysql running total, order by date

I have been trying to do a running total "order by date". The problem is that if you have two entries with the same date, then it shows the same total on both rows.
Table structure is something like this
sipID|Date|Amount
1|2017-11-07|2
2|2017-11-09|27
3|2017-11-07|24
So I know how to do a running total by id like this.
SELECT `sipID`,DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`,`Amount`,
(SELECT SUM(`Amount`) FROM `salesinvoice_payments` as `Lin` WHERE `Lin`.`sipID`<=`Lout`.`sipID` && `salesinvoice_id`=115) as `Balance`
FROM `salesinvoice_payments` as `Lout`
WHERE `salesinvoice_id`=115
ORDER BY `sipID`
But I wanted it to be ordered by date ascending so I did this
SELECT `sipID`,DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`,`Amount`,
(SELECT SUM(`Amount`) FROM `salesinvoice_payments` as `Lin` WHERE `Lin`.`Date`<=`Lout`.`Date` && `salesinvoice_id`=115) as `Balance`
FROM `salesinvoice_payments` as `Lout`
WHERE `salesinvoice_id`=115
ORDER BY `Date` ASC
Now this does work. The problem happens when you have 2 rows with the same date. What happens then is that both rows have the same running total.
eg
07 November 2017 2.00 24.00
07 November 2017 22.00 24.00
09 November 2017 3.00 27.00
What I want is this
07 November 2017 2.00 2.00
07 November 2017 22.00 24.00
09 November 2017 3.00 27.00
Is there a workaround so that I can have a proper running total, and have it ordered by date without it getting the same total on the same date?
EDIT:
#Strawberry:
I have finally worked out how sqlfiddle works, and put this for my original question.
http://www.sqlfiddle.com/#!9/c6dc75/1
You need something to separate Ammount from same day.
SQL DEMO
SELECT `sipID`,
DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`,
`Amount`,
(SELECT SUM(`Amount`)
FROM `salesinvoice_payments` as `Lin`
WHERE `Lin`.`Date` < `Lout`.`Date`
OR (`Lin`.`Date` = `Lout`.`Date`
AND `Lin`.`sipID` <= `Lout`.`sipID`)
) as `Balance`
FROM `salesinvoice_payments` as `Lout`
ORDER BY `Date` ASC
OUTPUT
Approach using user variables: DEMO with nod to Juan for setup of tables/data
SELECT `sipID`
, DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`
,`Amount`
,#Bal:=#Bal+`amount` as `Balance`
FROM `salesinvoice_payments` as `Lout`
CROSS JOIN (SELECT #Bal:=0) z --initializes and declares variable in select
WHERE `salesinvoice_id`=115
ORDER BY `Date`, `sipID`
Or using pagination
SELECT *
FROM (SELECT `sipID`
, DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`
,`Amount`
,#Bal:=#Bal+`amount` as `Balance`
FROM `salesinvoice_payments` as `Lout`
CROSS JOIN (SELECT #Bal:=0) z --initializes and declares variable in select
WHERE `salesinvoice_id`=115
ORDER BY `Date`, `sipID`) Z
ORDER BY `DateFormat`, `sipID`
LIMIT 5,10; -- Retrieve rows 6-15 Skip 5 retrieve next 10.
In this approach the variables have already been resolved in set {Z} thus the user variables are not impacted by the Limit/offset.
Example using your SQL Fiddle but we would need more sample data to really see the pagination impact.

mysql counts in a month and total counts upto month

I want the count of records in every month and total count of records from start upto that month.
For ex.,
I have a table that looks like this:
#id,created#
1,'2016-01-01'
2,'2011-02-02'
3,'2011-02-09'
4,'2011-02-05'
5,'2011-03-07'
6,'2011-03-08'
How do I select and group these so the output is:
#Month, new, total#
Jan 2016, 1, 1
Feb 2016, 3, 4
Mar 2016, 2, 6
Thanks very much.
Here you go:
SELECT DATE_FORMAT(`created`,'%M %Y') AS month, COUNT(*) AS count,
(SELECT count(*) FROM test WHERE MONTH(created) <= MONTH(t.created)) AS total
FROM test t
GROUP BY MONTH(created);
Here's the SQL Fiddle.
Using single table read:
SELECT
CONCAT(LEFT(MONTHNAME(dt), 3), ' ', YEAR(dt)) month,
new,
#total:=#total + new total
FROM
(SELECT
created - INTERVAL DAY(created) - 1 DAY dt, COUNT(*) new
FROM
t
GROUP BY created - INTERVAL DAY(created) - 1 DAY
ORDER BY dt) t
CROSS JOIN
(SELECT #total:=0) t2
Demo

MySQL: counts by week.

I would like to group a series of counts but by week. I know that using the week() function returns a number for the week, but i'd like something like this:
Week count(*)
Jan 1 - Jan 7 30
Jan 8 - 14 50
and so on...
Is there a way to do this? Thank you very much.
select
concat(cast(DATE_ADD(yourdate, INTERVAL(1-DAYOFWEEK(yourdate)) DAY) as char), ' - ',
cast(DATE_ADD(yourdate, INTERVAL(7-DAYOFWEEK(yourdate)) DAY) as char))
as period, count(*)
from tablename
group by week(yourdate)