I'm trying to display all dates in a month, and also in the reservation detail, I only have check_in_date and check_out_date, so I have to create left join inside a left join, below is my script
SELECT
*
FROM
(
SELECT
#dt:= DATE_ADD( #dt, interval 1 day ) myDate
FROM
(
SELECT
#dt := '2020-01-31'
) vars, tb_dummy
LIMIT 29
) JustDates
LEFT JOIN
(
SELECT
DATE_FORMAT(d.myDate2,'%Y-%m-%d') AS `myDate2`,
COALESCE(count(rdt.reservation_detail_id), 0) AS `RNS`,
FORMAT(SUM(rdt.subtotal_amount/COALESCE(DATEDIFF(DATE(DATE(rdt.check_out_date)), DATE(rdt.check_in_date)), 0)), 2) AS `REVENUE`,
FORMAT(SUM(rdt.subtotal_amount/COALESCE(DATEDIFF(DATE(DATE(rdt.check_out_date)), DATE(rdt.check_in_date)), 0))/COALESCE(count(rdt.reservation_detail_id), 0), 2) AS `AVGREV`
FROM
(
SELECT
#dt:= DATE_ADD( #dt, interval 1 day ) myDate2
FROM
(
SELECT
#dt := '2020-01-31'
) vars2, tb_dummy
LIMIT 29
) d
LEFT JOIN
tb_reservation_detail rdt
ON d.myDate2 BETWEEN DATE(rdt.check_in_date) AND DATE(DATE(rdt.check_out_date) - INTERVAL 1 DAY)
INNER JOIN
tb_reservation R
ON rdt.reservation_id = R.reservation_id
WHERE
rdt.reservation_status_id <> 3
AND
R.property_id = 57
GROUP BY d.myDate2
ORDER BY d.myDate2 ASC
) Resv
ON
JustDates.myDate = Resv.myDate2
ORDER BY
JustDates.myDate ASC
when i run it only return dates from the left table like : Left join result
but when I change
SELECT
*
FROM
(
SELECT
#dt:= DATE_ADD( #dt, interval 1 day ) myDate
FROM
(
SELECT
#dt := '2020-01-31'
) vars, tb_dummy
LIMIT 29
) JustDates
**LEFT JOIN**
(
to
SELECT
*
FROM
(
SELECT
#dt:= DATE_ADD( #dt, interval 1 day ) myDate
FROM
(
SELECT
#dt := '2020-01-31'
) vars, tb_dummy
LIMIT 29
) JustDates
**RIGHT JOIN**
(
it returns data from the right table like this: Right join result
What is wrong with my code?
welcome to StackOverflow. I think your problem is that you don't quite understand the difference between RIGHT JOIN and LEFT JOIN. Check out this StackOverflow post that goes over the differences.
As far as wanting to display all of the dates in a month, here's a link to an answer I posted that I believe does what you want it to. In my answer I provide an example query that contains a derived table you can select from and then LEFT JOIN your tables to so it will show all the days in the month regardless if there is data in your tables for a given day or not.
Hope this helps.
Related
I have a complex mysql query language, including several sub queries and my final result is as below. There is something that I am dealing with it and I can't solve it and this is a way result is being presented. I am wondering to know how can i change the structure of the result in a way that the result is being presented only in one row and I don't want to see NULL fields. I mean something like below
This is mysql query
select count(*) as userRetentionSameDay, null as 'userRetentionDiffDay' from (SELECT date(`timestamp`), `user_xmpp_login`
FROM table1
WHERE DATE(`timestamp` ) = CURDATE() - INTERVAL 1 DAY) as res1
right join (select date(ts), user
from table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
and product_id REGEXP ("^(europe+$" )) as lej1
on lej1.user = res1.`user_xmpp_login`
where res1.`user_xmpp_login` IS not NULL
union all
select null as 'userRetentionSameDay', count(*) as userRetentionDiffDay from (SELECT date(`timestamp`), `user_xmpp_login`
FROM table1
WHERE DATE(`timestamp` ) = CURDATE() - INTERVAL 1 DAY) as res1
right join (select date(ts), user
from table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
and product_id REGEXP ("^(europe+$" )) as lej2
on lej2.user = res1.`user_xmpp_login`
where res1.`user_xmpp_login` IS NULL;
What are the recommended solutions to doing that?
try this.
SELECT A.userRetentionSameDay,B.userRetentionDiffDay FROM (
SELECT COUNT() AS userRetentionSameDay FROM
(
SELECT DATE(timestamp), user_xmpp_login
FROM table1
WHERE DATE(timestamp ) = CURDATE() - INTERVAL 1 DAY) AS res1
RIGHT JOIN (SELECT DATE(ts), USER
FROM table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
AND product_id REGEXP ("^(europe+$" )) AS lej1
ON lej1.user = res1.user_xmpp_login
WHERE res1.user_xmpp_login IS NOT NULL
) A,
(
SELECT COUNT() AS userRetentionDiffDay FROM (
SELECT DATE(timestamp), user_xmpp_login
FROM table1
WHERE DATE(timestamp ) = CURDATE() - INTERVAL 1 DAY
) AS res1
RIGHT JOIN (SELECT DATE(ts), USER
FROM table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
AND product_id REGEXP ("^(europe+$" )
) AS lej2
ON lej2.user = res1.user_xmpp_login
WHERE res1.user_xmpp_login IS NULL
) B;
I have a table with data like below, and I'm trying to sum up column b and group by day. This works great. However some days have no data in the table at all. I want to show these days as having the sum 0, but I'm a bit confused on how to get there.
Date, column b
05/24/90, 5
05/24/90, 27
05/26/90, 19
05/27/90, 24
What I want to have in the end is
05/24/90, 32
05/25/90, 0
05/25/90, 19
05/27/90, 24
etc...
Something like this should work:
DECLARE #MinDate DATE = (SELECT MIN([date]) FROM yourTable);
DECLARE #MaxDate DATE = (SELECT MAX([date]) FROM yourTable);
WITH CTE_dates
AS
(
SELECT #MinDate dates
UNION ALL
SELECT DATEADD(DAY,1,dates)
FROM CTE_dates
WHERE dates < #MaxDate
)
SELECT A.dates,
SUM(ISNULL(B.[column b],0))
FROM CTE_dates A
LEFT JOIN yourTable
ON A.dates = B.dates
GROUP BY A.dates
I got the following code:
SELECT
COALESCE(rv.views, 0) as views
FROM
( select 0 as n
union all select 1
union all select 2
union all select 3 ) n
LEFT JOIN restaurant_views rv
on rv.date = date_add("2015-02-24", interval - n.n day)
and restaurant_id = 192
This code is giving me the amount of views a restaurant had the last 4 days.
I am looking for a similar query to get the amount of likes a restaurant had the last 4 days.
This is what I got so far:
SELECT
( COUNT( DISTINCT a.restaurant_id)
+ COUNT( DISTINCT d.restaurant_id)) as num_likes
FROM
( select 0 as n
union all select 1
union all select 2
union all select 3 ) n
LEFT JOIN apple_likes a
on a.vote_date = date_add("2015-02-24", interval - n.n day)
and a.restaurant_id = 192
LEFT JOIN android_likes d
on d.vote_date = date_add("2015-02-24", interval - n.n day)
and d.restaurant_id = 192
And here is the output, which is as you can see not what I'm looking for:
What do I have to change to get the number of likes in the last query?
(I have checked that the restaurant has likes on all days, so I am positive it's something wrong with the query)
Try this one:
SELECT
( a.likes)
+ d.likes) as num_likes
FROM
( select 0 as n
union all select 1
union all select 2
union all select 3 ) n
LEFT JOIN (
SELECT vote_date,COUNT(*) as likes
FROM apple_likes
WHERE restaurant_id = 192
GROUP BY restaurant_id, vote_date
) as a
on a.vote_date = date_add("2015-02-24", interval - n.n day)
LEFT JOIN (
SELECT vote_date, COUNT(*) as likes
FROM android_likes
WHERE restaurant_id = 192
GROUP BY restaurant_id, vote_date
) as d
on d.vote_date = date_add("2015-02-24", interval - n.n day)
I can think of a couple items that might be what you are encountering...
Just because somebody VIEWS a restaurant, does that mean they actually VOTED??? And if Voted, are the only two devices that of apple or android? What if viewing from a browser and they are on a Windows machine browser-based?
Date Equality. In the restaurant views table, is the date field ALWAYS that of a time = 12:00:00 (ie: midnight/morning of the day). If the time-stamps of the votes are anything other than 12:00:00, and you are trying to compare for a date = date + time is probably failing. What you may need is a comparison of the date( vote_date ) = date( date_add( ... )) so this way BOTH are ignoring the time component... Now, that being said, a function on a date column is not going to be optimized, even if the restaurant ID is numeric and part of the index key... it would be PARTIALLY optimized. You may want to just add a generic date of AND vote_date >= '2015-02-20' so it can optimize the restaurant and date, then apply the DATE( vote_date ) for the actual qualfying of records.
Got a good one here...
I currently have the following bit of code that basically sums the total of active accounts by month.
That is simple, however what I'm wanting to do the same thing on a per category basis and over a defined period and not just one month Ie. over 12 months.... Any ideas / assistance please....My brain is flat :(
SELECT
DATE_FORMAT(s.`DateCreated`,'%Y-%M') AS `Date Created`
, DATE_FORMAT(s.`DateEnd`,'%Y-%M') AS `Date End`
,(#csum := #csum + COUNT(DISTINCT(acc.`AccountId`))) AS Active
FROM (SELECT #csum := 0) AS csums, xx_accountdetails acc
INNER JOIN xx_services s USING(accountid)
LEFT JOIN xx_category cat ON(CategoryId)
INNER JOIN xx_products prod USING(productid)
LEFT JOIN xx_subcategory sc ON(prod.Subcategoryid = sc.SubCategoryId)
LEFT JOIN xx_invoiceline il USING(serviceid)
LEFT JOIN xx_invoices i USING(invoiceid)
WHERE DATE_FORMAT(s.DateStart,'%Y-%m') <= DATE_SUB(NOW(), INTERVAL 1 MONTH)
AND
s.`ProductId` NOT IN (4001,4002)
AND cat.`CategoryId` = '1'
AND
(DATE_FORMAT(s.`DateEnd`,'%Y-%m') >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
OR
(s.`DateEnd` IS NULL
AND s.`IsActive` = 1
AND (s.`SuspendReasonId` != 3 OR s.`SuspendReasonId` IS NULL)))
GROUP BY DATE_FORMAT(s.DateCreated,'%Y-%m')
For the date range, simply change the date intervals, e.g.:
date_sub(now(), interval 12 months)
For the per categories, you need to add an extra group by statement:
group by cat.CategoryId, ...
Remove the where clause on it, too, else you'll only have CategoryId = 1.
Hi all i execute this query to get a table where there's statistics of some database information.. i'd like to intialise the fields that don't exist ( because the query is executed in different dates and sometimes there's a day where there's nothing ) so i'd like it to return 0 and NULL ( in TOP column )
SELECT
SUM(IF(`TOP` = 'one',`Nb`,0)) as first_one,
SUM(IF(`TOP` = 'two',`Nb`,0)) as second_one,
SUM(IF(`TOP` = 'three',`Nb`,0)) as thrid_one,
SUM(IF(`TOP` NOT IN ('three','two','one'),`Nb`,0)) as forth_one,
GROUP_CONCAT(IF(`TOP` NOT IN ('three','two','one'),`TOP`,'') SEPARATOR '') as `OR`
FROM (
SELECT
COUNT(*) as Nb,
'one' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
UNION ALL
SELECT
COUNT(*) as Nb,
'two' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND S=0
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
UNION ALL
SELECT
COUNT(*) as Nb,
'three' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND S<>0
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
UNION ALL
SELECT
`Nb`,
`TOP`
FROM(
SELECT
COUNT(*) as Nb ,
`OR` as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
GROUP BY
`OR`
ORDER BY
Nb DESC
LIMIT 1
) as tmp
)as tmp1
Assuming that in tmp1 you have data you need but with "gaps" (days when there were no data at all) you could RIGHT JOIN tmp1 to table tmp2 using day (I assume that you have such column in tmp1 table). So tmp2 would be just list of days:
SELECT '2013-05-17' as day UNION SELECT '2013-05-18' UNION SELECT ...
I could elaborate my answer if you'd like to provide your DB schema.
You can replace each subquery with:
SELECT
IFNULL(tmp.Nb,0) as Nb,
IFNULL(tmp.`TOP`, 'value') as `TOP`
FROM (
--subquery
) as tmp
Example for the first subquery:
SELECT
IFNULL(tmp.Nb,0) as Nb,
IFNULL(tmp.`TOP`, 'one') as `TOP`
FROM (
SELECT
COUNT(*) as Nb,
'one' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
) as tmp
SQL is good at grouping existing entities into categories, but bad at "creating" entities itself. I would advise either a generic number table (really just the numbers from 0 to a few hundredthousand) if you have also non-date categories or as Wiktor suggested a date-Table which gets filled every now and then and has the next few years as well as the time since your program is working.
With a date table
list_dates (
id int(11) not null primary key auto_increment,
dateval date not null
)
you could start your queries from that table (with a reasonable range, of course) and count every thing else:
select list_dates.dateval as date, count(*) as cnt
from list_dates
left join actions on actions.actiontime >= (cast list_dates.date_val as datetime)
and actions.actiontime < (cast list_dates.date_val `interval 1 day as datetime)
where list_dates.dateval between '$fromDate' and '$toDate'
group by list_dates.dateval
;
or starting with a number table numbers
select $fromDate + interval numbers.number day as date, count(*) as cnt
from numbers
left join actions
on actions.actiontime >= (cast $fromDate + interval numbers.number day as datetime)
and actions.actiontime < (cast $fromDate + interval (1 + numbers.number) day as datetime)
where numbers.number >= 0 and numbers.number < $countDates
group by numbers.number
;
One Day
If you really want just that one day (today) then you can of course use a anonymous subselect- Table instead, so it becomes
select list_dates.dateval as date, count(*) as cnt
from ( select curdate() as dateval ) as list_dates
left join actions on actions.actiontime >= (cast list_dates.date_val as datetime)
and actions.actiontime < (cast list_dates.date_val `interval 1 day as datetime)
where list_dates.dateval between '$fromDate' and '$toDate'
group by list_dates.dateval
;