I have events table with columns
'title',
'description',
'start_date',
'end_date'.
I want to get ordered list live and future events, depends on 'start_date' and 'end_date'.
I try
(
select *
from `events`
where `start_date` < NOW() and `end_date` > NOW()
order by `start_date` desc
)
union all
(
select *
from `events`
where `start_date` > NOW()
order by `start_date` desc)
but result have not that ordering which I want. I want at first ordered list by start_date live events after that ordered list by start_date future events.
I think you do not need union in this one.
Just put a OR condition in your basic query.
Then, to split the result into "this one is live" and "this one is future" you can use a flag
SELECT *, start_date < NOW() AS flag
FROM `events`
WHERE (`start_date` < NOW() and `end_date` > NOW())
OR `start_date` > NOW()
ORDER BY flag DESC, start_date
Nota : the DESC is here to show you you want live before future event. Otherwise just put ASC.
Try this:
select * from (
(
select start_date, end_date, 'Live' as event_type
from `events`
where `start_date` < NOW() and `end_date` > NOW()
)
union
(
select start_date, end_date, 'Future' as event_type
from `events`
where `start_date` > NOW() ) ) a
ORDER BY event_type desc
, case when event_type = 'Live' then start_date end desc
, case when event_type = 'Future' then start_date end asc;
Why can't you just select all events ordered by start_date?
select *
from `events`
where (`start_date` < NOW() AND `end_date` > NOW())
or (`start_date` > NOW())
order by `start_date` desc
Anyway live events will be first, then future events
Related
I have house_leases and house_lease_terms (see table schemas below). A house_lease can have multiple house_lease_terms however there can only be one "active" term at a time.
Table Definitions:
CREATE TABLE `house_leases` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`house_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `house_lease_terms` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`house_lease_id` int(10) unsigned NOT NULL,
`date_start` datetime NOT NULL,
`date_end` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `house_lease_terms_house_lease_id_foreign` (`house_lease_id`),
CONSTRAINT `house_lease_terms_house_lease_id_foreign` FOREIGN KEY (`house_lease_id`) REFERENCES `house_leases` (`id`) ON DELETE CASCADE
);
As you can see the house_lease_terms.house_lease_id corresponds to a specific house_lease, however there can be multiple rows with the same house_lease_id.
The rules for determining the "active" terms are:
date_start <= NOW() AND date_end > NOW() OR date_end IS NULL
If no rows are returned then the "active" terms must be in the future, so then the rules change to be:
date_start > NOW()
We order by date_start DESC if the terms are not in the future since multiple rows could be returned we want the latest date_start at the top of the results. Otherwise we sort by date_start ASC because we want the closest date_start to now to be at the top.
I then limit by 1 to get only one result and that row is considered the "active" terms. If no results come back, then there are no "active" terms.
I have a SQL statement that has this logic for getting a specific house_lease_id. That looks like this:
SELECT * FROM house_lease_terms
WHERE
CASE
WHEN
(SELECT COUNT(*) FROM house_lease_terms WHERE date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL) AND house_lease_id = 1)
THEN
date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL)
ELSE
date_start > NOW()
END
AND house_lease_id = 1
ORDER BY
IF(
(SELECT COUNT(*) FROM house_lease_terms WHERE date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL) AND house_lease_id = 1),
unix_timestamp(date_start),
-unix_timestamp(date_start)
) DESC
LIMIT 1;
This statement works, but I wish there was a better way (more efficient) of fetching the "active" terms for a specific house_lease_id (If you know a better solution please share).
Now I need to have a query that will fetch the "active" terms for all the different house_lease_id's.
I don't want any type of custom MySQL function or stored procedure to do this. I don't know where to start to create this query. I figure I can use the query from above in some sub select or join, but am not sure how I would do so.
Any help will be appreciated!
SQLFiddle with data: http://sqlfiddle.com/#!9/cab159/2/0
Look for:
SELECT *
FROM house_lease_terms
WHERE house_lease_id = 1
AND ( ( ( date_start <= NOW()
AND date_end > NOW()
)
OR date_end IS NULL
)
OR (date_start > NOW()
)
)
ORDER BY CASE WHEN ((date_start <= NOW() AND date_end > NOW()) OR date_end IS NULL)
THEN DATEDIFF(NOW(), date_start)
ELSE DATEDIFF(date_start, NOW()) + 1000000
END
SELECT id,
CASE WHEN #var2=house_lease_id
THEN #var1:=house_lease_id
ELSE 1
END row_number_in_house_lease_id,
#var2:=house_lease_id house_lease_id,
date_start,
date_end,
created_at,
updated_at,
deleted_at
FROM house_lease_terms, (SELECT #var1:=0, #var2:=0) variables
WHERE house_lease_id = 1
AND ( ( ( date_start <= NOW()
AND date_end > NOW()
)
OR date_end IS NULL
)
OR (date_start > NOW()
)
)
ORDER BY house_lease_id,
CASE WHEN ((date_start <= NOW() AND date_end > NOW()) OR date_end IS NULL)
THEN DATEDIFF(NOW(), date_start)
ELSE DATEDIFF(date_start, NOW()) + 1000000
END
Next generation.
SELECT id, house_lease_id, date_start, date_end
FROM (
SELECT id,
CASE WHEN #var2=house_lease_id
THEN #var1:=#var1+1
ELSE #var1:=1
END row_number_in_house_lease_id,
#var2:=house_lease_id house_lease_id,
date_start,
date_end
FROM house_lease_terms, (SELECT #var1:=0, #var2:=0) variables
WHERE ( ( ( date_start <= NOW()
AND date_end > NOW()
)
OR date_end IS NULL
)
OR (date_start > NOW()
)
)
ORDER BY house_lease_id,
CASE WHEN ((date_start <= NOW() AND date_end > NOW()) OR date_end IS NULL)
THEN DATEDIFF(NOW(), date_start)
ELSE DATEDIFF(date_start, NOW()) + 1000000
END
) AS cte
WHERE row_number_in_house_lease_id = 1;
fiddle
I'm not sure this is what you would consider clean, but it seems like any approach to this is going to result in a fairly complex and messy query.
Based on your original query:
SELECT house_lease_id,
SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY
IF(
(SELECT COUNT(*) FROM house_lease_terms AS hlt2
WHERE date_start <= NOW()
AND (date_end > NOW() OR date_end IS NULL)
AND hlt2.house_lease_id = hlt.house_lease_id),
unix_timestamp(date_start),
-unix_timestamp(date_start)
) DESC),',',1) AS id,
SUBSTRING_INDEX(GROUP_CONCAT(date_start ORDER BY
IF(
(SELECT COUNT(*) FROM house_lease_terms AS hlt3
WHERE date_start <= NOW()
AND (date_end > NOW() OR date_end IS NULL)
AND hlt3.house_lease_id = hlt.house_lease_id),
unix_timestamp(date_start),
-unix_timestamp(date_start)
) DESC),',',1) AS date_start,
SUBSTRING_INDEX(GROUP_CONCAT(date_end ORDER BY
IF(
(SELECT COUNT(*) FROM house_lease_terms AS hlt4
WHERE date_start <= NOW()
AND (date_end > NOW() OR date_end IS NULL)
AND hlt4.house_lease_id = hlt.house_lease_id),
unix_timestamp(date_start),
-unix_timestamp(date_start)
) DESC),',',1) AS date_end
FROM house_lease_terms AS hlt
WHERE
CASE
WHEN
(SELECT COUNT(*) FROM house_lease_terms AS hlt5 WHERE date_start <= NOW()
AND (date_end > NOW() OR date_end IS NULL)
AND hlt5.house_lease_id = hlt.house_lease_id)
THEN
date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL)
ELSE
date_start > NOW()
END
GROUP BY hlt.house_lease_id;
That should work.
I'm know this can be written as a single SQL statement, but I just don't know how to do it. I have two separate queries. Ont that pulls all orders from a specific period of last year
SELECT * FROM `order` WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01';
and one that pulls from the last month
SELECT * FROM `order` WHERE date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now() ORDER BY date_added ASC
What I want to do is now join the two so that I only get the customer_id of orders that were placed inside of the date range last year (query 1), but haven't placed an order in the last month (query 2).
I know there is a way to set this up as a join, but my knowledge on sql join's is not very limited. Thanks for any help.
http://sqlfiddle.com/#!9/35ed0/1
SELECT * FROM `order`
WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01'
AND customer_id NOT IN (
SELECT DISTINCT customer_id FROM `order`
WHERE date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now())
UPDATE If you need only 1 records per customer_id, here is an example . It is not very best from performance perspective. But it returns only last (according to the date_added column) order per customer.
SELECT t.*,
if(#fltr=customer_id, 0, 1) fltr,
#fltr:=customer_id
FROM (SELECT *
FROM `order`
WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01'
AND customer_id NOT IN (
SELECT DISTINCT customer_id FROM `order`
WHERE date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now())
ORDER BY customer_id, date_added DESC
) t
HAVING (fltr=1);
I usually use a correlated not exists predicate for this as I feel that it corresponds well with the intent of the question:
SELECT *
FROM `order` o1
WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01'
AND NOT EXISTS (
SELECT 1
FROM `order` o2
WHERE date_added BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()
AND o1.customer_id = o2.customer_id
);
I like to approach these questions using group by and having. You are looking for customer ids, so:
select o.customer_id
from orders o
group by o.customer_id
having sum(date_added BETWEEN '2014-10-01' AND '2014-11-01') > 0 and
sum(date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now()) = 0;
Original Query:
// Doesn't return dates with zero value
SELECT UNIX_TIMESTAMP( created_at ) AS DATE, COUNT( tweet_id ) AS count
FROM `tweets`
WHERE DATE( created_at ) > '2012-11-01'
AND DATE( created_at ) <= DATE( NOW( ) )
GROUP BY DATE
Modified Query:
// Attempting to return all dates with a value of zero if doesn't exist in `created_at` column
CREATE TEMPORARY TABLE DateSummary1 ( date timestamp ) SELECT DISTINCT(DATE(created_at)) as date FROM tweets;
CREATE TEMPORARY TABLE DateSummary2 ( date timestamp, number int ) SELECT DATE(created_at) as date, count(*) AS number FROM tweets WHERE DATE(created_at) > '2012-11-01' AND DATE(created_at) <= DATE(NOW()) GROUP BY DATE(created_at) ORDER BY created_at ASC;
SELECT ds1.date,ds2.number FROM DateSummary1 ds1 LEFT JOIN DateSummary2 ds2 on ds1.date=ds2.date;
Unfortunately, the latter result isn't providing me the dates with zero values like I had expected. What am I overlooking? I'm sure this is a logic error, but I'm not sure where my logic has faulted. I've gotten this far from reading copious threads on SO, Google, etc. but am not sure how to get over this final hurdle.
An example of the returned timestamps using jcho360's suggestion:
1387286811
1387286812
1387286813
1387286815
1387286820
Try this
SELECT UNIX_TIMESTAMP( created_at ) AS DATE, COUNT( tweet_id ) AS count
FROM `tweets`
WHERE (DATE( created_at ) > '2012-11-01'
AND DATE( created_at ) <= DATE( NOW( ) ) )
or DATE( created_at ) = date ('000-00-00') //I added this Line
GROUP BY DATE
SELECT * FROM `user`
WHERE name !='' AND `date_created` BETWEEN DATE_SUB( CURDATE( ) ,INTERVAL 3 Day )
AND DATE_SUB( CURDATE( ) ,INTERVAL 0 Day )
ORDER BY `date` ASC
The above query brings record 3day before from todays date.
but i need 3day records from today,which means tomorrow , day after tomorrow etc.
date_created is mysql date format.
SELECT * FROM `user`
WHERE name !=''
AND `date_created` BETWEEN curdate() and curdate() + interval 3 day
ORDER BY `date`
I have created this will return previous 3 days record
select * from events where DATEOFEVENT IN (select date(curdate()-3 ))
I'm new to tsql and use mysql db. Seen an example code(at below) to get data from database every 2 hour:
SELECT date(`dateTime`) dateDay, 2*floor(date_format(`dateTime`,'%H')/2) dateHour,
avg(channel1), avg(channel2), avg(channel3)
FROM `Table`
WHERE `id` =1
AND `dateTime` >= '2011-10-15 00:00:01'
AND `dateTime` <= '2011-10-17 23:59:59'
Then I did few changes based on the above code to get data every 15 minutes:
SELECT date(`dateTime`) dateDay, 15*floor(date_format(`dateTime`,'%i')/15) dateHour,
avg(channel1), avg(channel2), avg(channel3)
FROM `Table`
WHERE `id` =1
AND `dateTime` >= '2011-10-15 00:00:01'
AND `dateTime` <= '2011-10-17 23:59:59'
group by date(`dateTime`), 15*floor(date_format(`dateTime`,'%i')/15)
However the query is not correct.
My questions are:
How to amend the query to get data every 15 min?
How to write sql query to get all data as well? and dateDay and dateHour columns need to be here.
1: every 15 minutes:
SELECT date(dateTime) dateDay, 2*floor(date_format(dateTime,'%H')/2) dateHour,
avg(channel1), avg(channel2), avg(channel3)
-->
SELECT date(`dateTime`) dateDay
,CONCAT( 2*floor(date_format(`dateTime`,'%H')/2), ':', 15*FLOOR(DATE_FORMAT(`dateTime`, '%i')/15)) dateQuarter
,avg(channel1), avg(channel2), avg(channel3)
FROM `Table`
WHERE `id` =1
AND `dateTime` >= '2011-10-15 00:00:01'
AND `dateTime` <= '2011-10-17 23:59:59'
GROUP BY 1,2;
2: all data. I wasn't really sure what you wanted. but here's every row with hour:minute in dateHour field.
SELECT date(`dateTime`) dateDay,
,DATE_FORMAT(`dateTime`, '%H:%i') dateHour,
FROM `Table`
WHERE `id` =1
AND `dateTime` >= '2011-10-15 00:00:01'
AND `dateTime` <= '2011-10-17 23:59:59'