I have a database that has payments called PrePay. Customers pay 12 months in one payment.
I need to have this single payment show up as 12 payments (12 records).
Here's my query:
SELECT account, startdate, servdef
FROM PAYHIST
WHERE account = 5543
startdate is a date field
This shows the 3 payments over 3 years:
I would like to produce 11 payments for each account and servdef after the first payment. So the 06-22-2018 would have 11 records following it with the months to follow i.e.
Can you please tell me how to produce the records like this?
Join with a table that returns the number of months you want to expand each row to.
SELECT account, DATE_ADD(startdate, INTERVAL n MONTH) AS startdate, servdev
FROM PAYHIST
CROSS JOIN (
SELECT 0 AS n
UNION
SELECT 1
UNION
SELECT 2
...
UNION
SELECT 11) AS q
WHERE account = 5543
ORDER BY startdate, n
Related
I want to display registered users each month on my web app. To achieve this I suppose to query the count from the user's table and send it to the front end. As an example, I get the count of users in one month from the following query.
select count(u_id) AS 'Count', MONTH(reg_date) AS Month
from user
WHERE(reg_date) BETWEEN '2019-10-01' AND '2019-10-31'
This displays the number of users registered in October. The resulting table I get from this query is this.
------------------------
Count Month
------------------------
2 10
------------------------
The result I want to get is the following one.
------------------------
Count Month
------------------------
2 1
------------------------
10 2
------------------------
5 3
------------------------
I have stored the user ID and register date in the user table. register date is SQL date type and UserID is Integer. I can get the number of users in a given month using the query I have mentioned below and store it in a variable in backend and call again database to get the next month and so on(Using a loop). Then create a list and send to the frontend. But for this I have to call the database several times. For getting the users of 12 months I have to query 12 times.
What I want is to get the number of users in each month from just one query. If I store the date as three columns like date, month, year I can get this result. But I do not wish to change the current table structure. Is there any way to approach this task without changing the current table sturcture?
What you are looking for is GROUP BY.
SELECT count(u_id) AS 'Count', MONTH(reg_date) AS Month
from user
WHERE(reg_date) BETWEEN '2019-01-01' AND '2019-12-31'
GROUP BY YEAR(reg_date), MONTH(reg_date);
First is to generate months 1 to 12, then join your original query based on month.
select t1.monthNo, t2.Count
from (select 1 as monthNo
union
select 2 as monthNo
union
select 3 as monthNo
union
select 4 as monthNo
union
select 5 as monthNo
union
select 6 as monthNo
union
select 7 as monthNo
union
select 8 as monthNo
union
select 9 as monthNo
union
select 10 as monthNo
union
select 11 as monthNo
union
select 12 as monthNo) as t1
left join
(select count(u_id) AS 'Count', month(reg_date) AS Month
from user
group by month(reg_date)) t2 on t2.Month = t1.monthNo
Input: I have a table that has a list of accounts and what they spent each day. For simplicity, we will say that the table has the following fields: account, account_id, date, sales.
Output: The end goal is to get a report of the Top 25 accounts and list their sales for the prior 8 weeks. The report will have the account, account_id, and then 8 additional columns for each of the prior 8 weeks with the sales summed in each column.
Problem 1: I'm having trouble grabbing the Top 25 accounts. I wrote a subquery to sum the prior month's sales for each account and grab the Top 25 by using the where clause with an in operator, but subqueries don't support in operators.
Problem 2: I am unsure how to pivot the 8 prior weeks into columns.
select
yearweek(date,1) as year_week
,date_add(makedate(year(date),1), interval week(date,1) week) as first_day_of_week
,account_id
,account
,sum(sales) as total_sales
from daily_sales
where date >= date_sub(curdate(), interval 8 week)
and account_id in ( select
account_id
from daily_sales
where year(date)=2018 and month(date)=11
group by 1
limit 25)
group by 1,2,3,4;
I have to do a SQL query for getting the incomes of a company on all the months of the year, but some months dont have records in the table.
I have used this query:
SELECT COUNT(wp_dgl_stats.datetime_stamp)*wp_dgl_ads.price as incomes, MONTHNAME(wp_dgl_stats.datetime_stamp) as month
FROM wp_dgl_ads
INNER JOIN wp_dgl_stats ON wp_dgl_stats.id_ad = wp_dgl_ads.id
WHERE YEAR(wp_dgl_stats.datetime_stamp) = 2015
GROUP BY MONTHNAME(wp_dgl_stats.datetime_stamp)
I have to say that wp_dgl_stats contains a record for every click made by an user in certain spaces of the web (the ads showed) with a reference to the ad and a datetime stamp.
This query returns exactly months with incomes and the exact amount. But I need to get also the rest of the months with a 0.
How could this be done?
After a lot of tests I got a proper solution. I will post it here if someone needs for it with an explanation.
SELECT meses.month, CAST(COUNT(stats.id)*ads.precio AS UNSIGNED) as precio
FROM
(
SELECT 1 AS MONTH
UNION SELECT 2 AS MONTH
UNION SELECT 3 AS MONTH
UNION SELECT 4 AS MONTH
UNION SELECT 5 AS MONTH
UNION SELECT 6 AS MONTH
UNION SELECT 7 AS MONTH
UNION SELECT 8 AS MONTH
UNION SELECT 9 AS MONTH
UNION SELECT 10 AS MONTH
UNION SELECT 11 AS MONTH
UNION SELECT 12 AS MONTH
) as meses
LEFT JOIN wp_dgl_stats stats ON meses.month = MONTH(stats.datetime_stamp)
LEFT JOIN wp_dgl_ads ads ON stats.id_ad = ads.id AND YEAR(stats.datetime_stamp) = '2015'
GROUP BY meses.month
Because I am a spanish developer and I need to have spanish month names I selected the month number and with an PHP array we can convert the month number to his spanish name.
If someone have some question, do it, I will be glad to answer.
You could LEFT/RIGHT join on the months:
WITH monthnames AS (SELECT <something that returns a list of the month names> as monthname)
SELECT COALESCE(COUNT(wp_dgl_stats.datetime_stamp)*wp_dgl_ads.price, 0) as incomes, MONTHNAME(wp_dgl_stats.datetime_stamp) as month
FROM wp_dgl_ads
INNER JOIN wp_dgl_stats ON wp_dgl_stats.id_ad = wp_dgl_ads.id
RIGHT JOIN monthnames ON month = monthname
WHERE YEAR(wp_dgl_stats.datetime_stamp) = 2015
GROUP BY MONTHNAME(wp_dgl_stats.datetime_stamp)
How do I write a query to display the cust_id and cust_name_last for each customer who had orders in two successive months in the current year. (successive meaning they follow each other 'may, june')
for example: customer 3 has orders in May and June of this year.
select cust_id, cust_name_last
from customer
where date_sub (order_date, interval 1 month)
and date_sub (order_date, interval 2 months)
"I just want to know how to find customers with orders in consecutive months in a year"
Could you try this?
SELECT DISTINCT month1.cust_id, month1.cust_name_last
FROM customer month1 INNER JOIN customer month2
ON month1.cust_id = month2.cust_id
AND YEAR(month2.order_date) = YEAR(month1.order_date)
AND MONTH(month2.order_date) - MONTH(month1.order_date) = 1;
If you want to find consecutive orders including another years (e.g 2013-12 => 2014-01), need to check overflows something like as follows
SELECT DISTINCT month1.cust_id, month1.cust_name_last
FROM customer month1 INNER JOIN customer month2
ON month1.cust_id = month2.cust_id
AND (YEAR(month2.order_date) - YEAR(month1.order_date)) * 12 + (MONTH(month2.order_date) - MONTH(month1.order_date)) = 1;
If preceding SQL does not work for you, We are highly appreciated when you post your schema and sample data on sqlFiddle http://www.sqlfiddle.com/.
Data:
values date
14 1.1.2010
20 1.1.2010
10 2.1.2010
7 4.1.2010
...
sample query about january 2010 should get 31 rows. One for every day. And values vould be added. Right now I could do this with 31 queries but I would like this to work with one. Is it possible?
results:
1. 34
2. 10
3. 0
4. 7
...
This is actually surprisingly difficult to do in SQL. One way to do it is to have a long select statement with UNION ALLs to generate the numbers from 1 to 31. This demonstrates the principle but I stopped at 4 for clarity:
SELECT MonthDate.Date, COALESCE(SUM(`values`), 0) AS Total
FROM (
SELECT 1 AS Date UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
--
SELECT 28 UNION ALL
SELECT 29 UNION ALL
SELECT 30 UNION ALL
SELECT 31) AS MonthDate
LEFT JOIN Table1 AS T1
ON MonthDate.Date = DAY(T1.Date)
AND MONTH(T1.Date) = 1 AND YEAR(T1.Date) = 2010
WHERE MonthDate.Date <= DAY(LAST_DAY('2010-01-01'))
GROUP BY MonthDate.Date
It might be better to use a table to store these values and join with it instead.
Result:
1, 34
2, 10
3, 0
4, 7
Given that for some dates you have no data, you'll need to fill in the gaps. One approach to this is to have a calendar table prefilled with all dates you need, and join against that.
If you want the results to show day numbers as you have showing in your question, you could prepopulate these in your calendar too as labels.
You would join your data table date field to the date field of the calendar table, group by that field, and sum values. You might want to specify limits for the range of dates covered.
So you might have:
CREATE TABLE Calendar (
label varchar,
cal_date date,
primary key ( cal_date )
)
Query:
SELECT
c.label,
SUM( d.values )
FROM
Calendar c
JOIN
Data_table d
ON d.date_field = c.cal_date
WHERE
c.cal_date BETWEEN '2010-01-01' AND '2010-01-31'
GROUP BY
d.date_field
ORDER BY
d.date_field
Update:
I see you have datetimes rather than dates. You could just use the MySQL DATE() function in the join, but that would probably not be optimal. Another approach would be to have start and end times in the Calendar table defining a 'time bucket' for each day.
This works for me... Its a modification of a query I found on another site. The "INTERVAL 1 MONTH" clause ensures I get the current month data, including zeros for days that have no hits. Change this to "INTERVAL 2 MONTH" to get last months data, etc.
I have a table called "payload" with a column "timestamp" - Im then joining the timestamp column on to the dynamically generated dates, casting it so that the dates match in the ON clause.
SELECT `calendarday`,COUNT(P.`timestamp`) AS `cnt` FROM
(SELECT #tmpdate := DATE_ADD(#tmpdate, INTERVAL 1 DAY) `calendarday`
FROM (SELECT #tmpdate :=
LAST_DAY(DATE_SUB(CURDATE(),INTERVAL 1 MONTH)))
AS `dynamic`, `payload`) AS `calendar`
LEFT JOIN `payload` P ON DATE(P.`timestamp`) = `calendarday`
GROUP BY `calendarday`
To dynamically get the dates within a date range using SQL you can do this (example in mysql):
Create a table to hold the numbers 0 through 9.
CREATE TABLE ints ( i tinyint(4) );
insert into ints (i)
values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
Run a query like so:
select ((curdate() - interval 2 year) + interval (t.i * 100 + u.i * 10 + v.i) day) AS Date
from
ints t
join ints u
join ints v
having Date between '2015-01-01' and '2015-05-01'
order by t.i, u.i, v.i
This will generate all dates between Jan 1, 2015 and May 1, 2015.
Output
2015-01-01
2015-01-02
2015-01-03
2015-01-04
2015-01-05
2015-01-06
...
2015-05-01
The query joins the table ints 3 times and gets an incrementing number (0 through 999). It then adds this number as a day interval starting from a certain date, in this case a date 2 years ago. Any date range from 2 years ago and 1,000 days ahead can be obtained with the example above.
To generate a query that generates dates for more than 1,000 days simply join the ints table once more to allow for up to 10,000 days of range, and so forth.
If I'm understanding the rather vague question correctly, you want to know the number of records for each date within a month. If that's true, here's how you can do it:
SELECT COUNT(value_column) FROM table WHERE date_column LIKE '2010-01-%' GROUP BY date_column