How to set variable in mySQL - mysql

I have the following statement:
SELECT
start_date,
end_date,
DATE(now()) BETWEEN start_date AND end_date should_be_live
FROM
mytable
WHERE
DATE(now()) BETWEEN start_date AND end_date should_be_live = 1
Is there a way to set a variable should_be_live = the expression DATE(now()) BETWEEN start_date AND end_date. If so, how would I do this?

If by "variable" you mean "column in the result set", then yes. You are basically doing it:
SELECT start_date, end_date,
( DATE(now()) BETWEEN start_date AND end_date) as should_be_live
FROM mytable;
If by "variable", you mean that you want to define a column in the select and then filter on it, you cannot do that with where (unless you use a subquery). You can use having:
SELECT start_date, end_date,
( DATE(now()) BETWEEN start_date AND end_date) as should_be_live
FROM mytable
HAVING should_be_live = 1;
This use of having is a MySQL extension.

No unfortunately, you will have to repeat the same expression DATE(now()) BETWEEN start_date AND end_date in your WHERE clause unless you are trying to access it in a outer query like
SELECT * FROM (
SELECT
start_date,
end_date,
DATE(now()) BETWEEN start_date AND end_date as should_be_live
FROM mytable ) xxx
WHERE should_be_live = 1;
Column alias are accessible only to GROUP BY, HAVING and ORDER BY clause and not to WHERE clause (that to it's a MySQL extension and not standard SQL)

Related

I'm using the IN operator yet I still get the error: 'Subquery returns more than 1 row'

I'm trying to solve this challenge: https://www.hackerrank.com/challenges/sql-projects/problem.
I tried the following:
SELECT
(SELECT start_date
FROM projects
WHERE
(SELECT DATE_ADD(start_date, INTERVAL -1 DAY)) NOT IN (SELECT start_date FROM projects)
ORDER BY start_date ASC) AS start_date,
(SELECT end_date
FROM projects
WHERE
(SELECT DATE_ADD(end_date, INTERVAL 1 DAY)) NOT IN (SELECT end_date FROM projects)
ORDER BY end_date ASC) AS end_date
FROM projects p
ORDER BY DATEDIFF(end_date, start_date) ASC, start_date ASC
Nonetheless,I got the following error: 'Subquery returns more than 1 row' Despite using the NOT IN operator.
However, when I tried executing only this part of the code:
SELECT start_date
FROM projects p
WHERE (SELECT (DATE_ADD(start_date, INTERVAL -1 DAY)) NOT IN (SELECT start_date FROM projects)
ORDER BY start_date ASC
It worked fine.
What could be the problem?
The two subquery for start _date and end_date could return a different numbers of rows adn any way the db engine not allow so called "parallel query"
in this case you should gets all the date involved and the left join for the subquery
select t1.start_date, t2.end_date
from (
SELECT start_date
FROM projects
WHERE DATE_ADD(start_date, INTERVAL -1 DAY) NOT IN (SELECT start_date FROM projects)
UNION
SELECT end_date
FROM projects
WHERE SELECT DATE_ADD(start_date, INTERVAL -1 DAY) NOT IN (SELECT end_date FROM projects)
) t
left join (
SELECT start_date
FROM projects
WHERE DATE_ADD(start_date, INTERVAL -1 DAY) NOT IN (SELECT start_date FROM projects)
) t1 on t.start_date = t1.start_date
left join (
SELECT end_date
FROM projects
WHERE DATE_ADD(start_date, INTERVAL -1 DAY) NOT IN (SELECT start_date FROM projects)
) t2 on t.start_date = t2.start_date
order by t1.syaty_date
You select project rows. Per project row you select a start date. The query for the this start date looks like this:
(SELECT start_date ... ORDER BY start_date ASC)
Do you really think it is one start_date you are selecting here? Why then the ORDER BY clause? This subquery returns multiple rows and this is why you are getting the error.
This query does not selects one start date, but all start dates for which not exists the previous date in the table. It doesn't even relate to the project row in the main query.
It seems you want to find all start dates that have no predecessor and all end dates that have no follower. These are two data sets you can select from. So the subqueries don't belong in the SELECT clause where you say which columns to select, but in the FROM clause where you say from which data sets to select.
You would then have to join the two sets. The join criteria would be the rows' positions in the ordered data sets (first start date belongs to first end date, second start date belongs to second end date, ...). For this you need a way to number these data rows.
Such a task is easy to solve with ROW_NUMBER. This is only featured since MySQL 8.
SELECT s.start_date, e.end_date
FROM
(
SELECT start_date, ROW_NUMBER() OVER (ORDER BY start_date) AS rn
FROM projects
WHERE start_date - INTERVAL 1 DAY NOT IN (SELECT start_date FROM projects)
) s
JOIN
(
SELECT end_date, ROW_NUMBER() OVER (ORDER BY end_date) AS rn
FROM projects
WHERE start_date + INTERVAL 1 DAY NOT IN (SELECT end_date FROM projects)
) e USING (rn)
ORDER BY s.start_date;
This kind of problem is called gaps & islands. There are other ways to solve this, but I think that above query plainly builds up on yours and is thus easy to understand.
Here is another answer that may explain better what you are doing.
You can:
select
start_date,
end_date,
start_date - interval 1 day as prev_day,
1 as one
from projects;
The select clause contains what you want to select from a projects row. For the first row you will get its start date, end date, its start date minus one day, and a 1 we call "one" here. For the second row you will get its start date (which is probably another start date than the one of the first row), its end date, its start date minus one day, and again a 1 we call "one".
You can
select
(select start_date) as start_date,
(select end_date) as end_date,
(select start_date - interval 1 day) as prev_day,
(select 1) as one
from projects;
which doesn't change anything and only obfuscates things. (This is what you do here: (SELECT DATE_ADD(end_date, INTERVAL 1 DAY)).
You cannot
select
(select start_date from projects) as start_date,
(select end_date from projects) as end_date,
(select start_date - interval 1 day from projects) as prev_day,
(select 1 from projects) as one
from projects;
because here you are not selecting one value for the first project row's start date, but all start dates from the table. Same for its end date etc. of course, same for the second row etc. This is what you are doing here:
SELECT
(SELECT start_date FROM projects ...) AS start_date,
(SELECT end_date FROM projects ...) AS end_date
FROM projects p
and this is why you are getting the error "Subquery returns more than 1 row".

MySQL Query in bad way

I have below query to check customer subscription. This is not quite right way to do in query but I do not know how to optimize or correct it. Here it is.
SELECT sub_id FROM subscription
WHERE start_date = CURDATE()
AND end_date > CURDATE()
AND sub_id NOT IN (SELECT DISTINCT sub_id FROM subscription
WHERE start_date < CURDATE());
The reason of sub query is to sieve out sub_id previously did at least a subscription.
You don't need SELECT DISTINCT sub_id FROM subscription WHERE start_date < CURDATE() subquery - you already have condition start_date = CURDATE().
SELECT sub_id FROM subscription
WHERE start_date = CURDATE()
AND end_date > CURDATE()
This query will select all subscriptions that start on CURDATE() and stop some other day in the future.

MySQL Update with same table subquery

I have a table (EMP_ID, START_DATE, END_DATE) that contains a series of date ranges. What I want to do is ensure that they are all contiguous, so the END_DATE should be one less than the next START_DATE for any given EMP_ID.
I have the following query that lets me identify the records that are not contiguous:
SELECT H.EMP_ID,
H.START_DATE,
H.END_DATE,
DATE(
( SELECT MIN(START_DATE)
FROM TSRHierarchy I
WHERE I.START_DATE > H.START_DATE
AND I.EMP_ID = H.EMP_ID
)
) AS NEXT_DATE
FROM TSRHierarchy H
HAVING END_DATE <> DATE_ADD(NEXT_DATE, INTERVAL -1 DAY)
ORDER BY H.EMP_ID, H.START_DATE;
What I can't do is figure out how to turn this into an UPDATE statement? The MySQL documentation states 'Currently, you cannot update a table and select from the same table in a subquery.' which may be part of my problem.
Any suggestions for a work-around?
Try this UPDATE query using JOIN
UPDATE TSRHierarchy t
JOIN
( SELECT H.EMP_ID,
H.START_DATE,
H.END_DATE,
DATE((SELECT MIN(START_DATE)
FROM TSRHierarchy I
WHERE I.START_DATE > H.START_DATE
AND I.EMP_ID = H.EMP_ID
)) AS NEXT_DATE
FROM TSRHierarchy H
HAVING END_DATE <> DATE_ADD(NEXT_DATE, INTERVAL -1 DAY)
) AS t2
ON t.EMP_ID = t2.EMP_ID
SET t.END_DATE = t2.NEXT_DATE

MySQL query to fetch result between start date and end date

I have two dates say start_date = 2013-04-12 and end_date = 2013-04-30
and my table contains row with start_date = 2013-04-12 and end_date = 2013-04-16
I want to fetch records whose start date is greater 2013-04-12 and end_date is less than 2013-04-30. Which includes above record having 2013-04-16 as end_date
I tried with this query
SELECT * FROM TABLE_NAME WHERE (start_date <='2013-04-12' AND end_date >='2013-04-30') which dont give any result however if i put end_date 2013-04-15 it works fine
SELECT
*
FROM
(
SELECT
'2013-04-12' as `start_date`,
'2013-04-16' as `end_date`
) `sub`
WHERE
(`start_date` BETWEEN '2013-04-12' AND '2013-04-30')
AND
(`end_date` BETWEEN '2013-04-12' AND '2013-04-30')
BETWEEN is more reliable
If you want to have start_date GREATER OR EQUAL 2013-04-12 and end_date LESSER OR EQUAL, than your operators are wrong:
start_date <='2013-04-12' AND end_date >='2013-04-30'
you should use >= for start_date and <= for end_date
like this:
start_date >='2013-04-12' AND end_date <='2013-04-30'
I think you are using wrong operators ... start_date greater than(>=) end_date less than equal to (<=)
SELECT * FROM TABLE_NAME WHERE (start_date >='2013-04-12' AND end_date <='2013-04-30')
I would do:
SELECT * FROM table_name WHERE start_date BETWEEN '2013-04-12' AND '2013-04-30'
Try this,
SELECT * FROM TABLE_NAME WHERE Convert(varchar,start_date,101) >'04/12/2013') AND convert(varchar,end_date,101) <'04/30/2013')

MySQL, get data between start and end date columns?

I've read a few similar questions then mine, where I could find queries that were pretty much the same I'm using. But I had to ask, because I would like to understand why this is not working:
I have the following data:
id category_id start_date end_date image campaign_id published
1 1 2011-07-05 2011-07-5 a.gif 3 1
2 1 2011-07-01 2011-07-15 c.gif 3 1
3 37 2011-07-01 2011-07-04 d.gif 3 1
I expect to get rows 1 and 2, from this query:
SELECT id, category_id, start_date, end_date FROM categories_campaigns WHERE start_date <= NOW() AND end_date >= NOW();
From what I've experienced, the only row returned is the second. Also this one, gives me the second,
SELECT category_id, start_date, end_date FROM categories_campaigns WHERE end_date >= NOW();
The next one returns me all 3,
SELECT category_id, start_date, end_date FROM categories_campaigns WHERE start_date <= NOW();
The datatype for both columns are DATE. So, my question is, how to solve this ? Why is this happening ? Or I've got an obvious error that I'm not finding on what to look for.
Working query
SELECT
category_id, start_date, end_date
FROM
categories_campaigns
WHERE
start_date <= DATE(NOW()) and end_date >= DATE(NOW());
I think you could use this:
SELECT category_id, start_date, end_date FROM categories_campaigns WHERE left(now(),10) between start_date and end_date;
I suppose start_date and end_date are of date datatype. But NOW() returns a date-time value.
Use CUR_DATE() instead of NOW()