check input value between two columns - mysql

Below is my database schema.
id from to value
1 1 10 5
2 11 NULL 10 -- I have stored 'NULL' for any value GREATER THAN 11
Now i have to select value where input like (4) is between from and to.
I know that it can be achieved with this query.
SELECT *
FROM TABLE
WHERE 4 BETWEEN `from` AND `to`
But how to select value where input is like 15?
SELECT *
FROM TABLE
WHERE 15 BETWEEN `from` AND `to`
In this case above query will not work because to column has null.
UPDATE
columen to will contain null if it can have any value.
Now If input value is 15, then query should return 2nd row, because 15 is not between 1 and 10 in 1st row and 15 is greater than 11 and to value can be anything greater than 11.

SELECT *
FROM TABLE
WHERE 15 BETWEEN coalesce(`from`,15) AND coalesce(`to`,15);

Use boolean combinations
select *
from table
where (to is not null and 15 between from and to)
or (to is null and 15 >= from)

SELECT *
FROM TABLE
WHERE 15 BETWEEN `from` AND IF_NULL(`to`,15)

Related

MySQL query with multiple BETWEEN is always NULL

Maybe I'm missing the obvious here, but why is this query always NULL?
SELECT ROUND(AVG(`viewer_count`),0) AS avg_viewer FROM `table`
WHERE
(id BETWEEN 1 AND 8)
AND
(id BETWEEN 26 AND 32)
Isn't it possible to get the average of multiple ranges like this?
Since it is not possible for an id to be between 1 and 8 and at the same time between 26 and 32, the query is returning NULL as no rows were matched. If you use OR as squemeamish suggested in the comment, you will get the average over both ranges.
SELECT ROUND(AVG(CASE WHEN id BETWEEN 1 AND 8 THEN `viewer_count` END),0) AS avg_viewer1_8
, ROUND(AVG(CASE WHEN id BETWEEN 26 AND 32 THEN `viewer_count` END),0) AS avg_viewer26_32
FROM `table`

Mysql search text in one column

For Example our table;
İd--------Price---------Level
1 ------100-300 ------ 1,2
2 ---------200----------1
3 ------100-280--------1,3
We want search a price value is 110. 110 is between 100-300 and 100-280 so id 1 and id 2 must listed. Can we write this query with my-sql?.
Additional , we want search price and level value. Price 110 and level 2 searching. Can we write this query with my-sql?.
Thank You
Remember that database tables should be created with the idea that it will satisfy your query needs. It doesn't make sense to have a table with a price "100-300" which represents a String (or in mysql a VARCHAR) and you want to treat this as a number. So what to do?
1) The first thing i would do is re write my table schema having a minPrice and maxPrice fields, so this way you could have this:
İd----minPrice---maxPrice------level
1 ------100---------300 ------ 1,2
2 ------200---------200----------1
3 ------100---------280--------1,3
2) Then your query would be like:
SELECT id FROM Mytable x WHERE myValue >= x.minPrice AND myValue <= x.maxPrice
3) In case you also want to look for a level value. you would do:
SELECT id FROM Mytable x WHERE myValue >= x.minPrice AND myValue <= x.maxPrice AND myLevelValue IN (x.level)
Use two columns for the price ...
ID FROM TO LEVEL
1 100 300 1,2
2 200 200 1
3 100 280 1,3
Then SQL:
SELECT `level` FROM `table`
WHERE X >= `from` AND X <= `to`

MySql Select Id <= Maximum value in the table

When using the <= in a MySql statement, is it possible to make MySql select the maximum value in a table without supplying a value to <= in the sql statement?
Eg:
id
----
1
2
3
4
5
6
Eg:
// start from the last record when no value is supplied
select id from table where id <= * ORDER BY id DESC LIMIT 5
Result
6
5
4
3
2
// start from the 5th record when a value is supplied
select id from table where id <= 5 ORDER BY id DESC LIMIT 5
Result
5
4
3
2
1
My problem is, this statement is in a php function, so I cannot change it dynamically. Is it somehow possible to do what I'm trying, or perhaps another way to get around this?
You can use NULL instead of using *
SET #var_search_value = NULL -- OR 5
SELECT id
FROM table
WHERE id <= #var_search_value OR #var_search_value IS NULL
ORDER BY id DESC LIMIT 5
If you want to get every record which is less than or equal to the maximum value in a particular column, then logically you want to get every record:
select id from table ORDER BY id DESC LIMIT 5
No WHERE clause is required.

MySQL Calculating sum over pairwise time differences of log file

i have a table in mysql to log user actions. Each row in the table corresponds to a user action, like login, logout etc.
The table looks like:
CREATE TABLE IF NOT EXISTS `user_activity_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`action_type` smallint NOT NULL,
`action_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
id user_id action_type action_created
...
22 6 1 2013-07-21 14:31:14
23 6 2 2013-07-21 14:31:16
24 8 2 2013-07-21 14:31:18
25 8 1 2013-07-21 14:45:18
26 8 0 2013-07-21 14:45:25
27 8 1 2013-07-21 14:54:54
28 8 2 2013-07-21 15:09:11
29 6 1 2013-07-21 15:09:17
30 6 2 2013-07-21 15:09:29
...
Imagine the action 1 is login and 2 is logout and that i want to find out the total time (in hours:minutes:seconds) the user with id 6 was logged in within a specific range of dates.
My first idea was to fetch all rows with either action 1 or 2 and calculate the date differences in PHP myself. This seems rather complicated and i am sure this can be done in one query with mysql, too!
What i tried was this:
SELECT TIMEDIFF(ual1.action_created, ual2.action_created) FROM user_activity_log
ual1,user_activity_log ual2 WHERE ual1.user_id = 6 AND ual2.user_id = 6 AND
ual1.action_type = 1 AND ual2.action_type = 2 AND
DATE(ual1.action_created) >= '2013-07-21' AND
DATE(ual1.action_created) <= '2013-07-21'
ORDER BY ual1.action_created
to select all login events from ual1 and all logout events from ual2 from the same user and then calculate the pairwise time difference for day 2013.7.21, which does not really work and i don't know why.
How can i calculate the total login time (sum over all time differences, date action 2 - date action 1)?
The result from the correct operation should be 2 seconds from log id pair 22,23 + 12 seconds from log id pair 29,30 = 14 seconds.
Thank you very much for your help in advance. Best regards
I think the easiest way to structure this type of query is using correlated subqueries (and, to be honest, I generally don't like correlated subqueries, but this is an exception). Your query would probably work with the right group by clause.
Here is an alternative method:
select TIMEDIFF(action_created, LogoutTS)
from (select ual.*,
(select ual2.user_activity_log
from user_activity_log ual2
where ual2.user_id = ual.user_id and
ual2.action_type = 2 and
ual2.action_created > ual.action_created
order by ual2.action_created desc
limit 1
) as LogoutTS
from user_activity_log ual
where ual.user_id = 6 and
ual.action_type = 1
) ual
To get the total, you then need to do something like sum(TIMEDIFF(action_created, LogoutTS). However, this can depend on the format of the time column. It might look something like this:
select SUM((UNIX_TIMESTAMP(LogoutTS) - UNIX_TIMESTAMP(action_created))/1000)
Or:
select sec_to_time(SUM((UNIX_TIMESTAMP(LogoutTS) - UNIX_TIMESTAMP(action_created))/1000))

I can't compare sql_variant field with IS NULL operator

I mean I can't query null values when column type sql_variant
For example docsdate table look like this:
ValID DocID Value <--sql variant column)
1. 488 146 30.10.2007
2. 740 190 31.03.2008
3. 570 161 31.10.2008
4. 242 103 NULL
5. 248 104 NULL
When query like select * from docsdate where value is null
no rows returned
Any idea?
This works fine for me. Are you sure your NULL values are actually proper NULLs and not strings containing the text NULL? Do they show up with a yellow background in SSMS?
create table #docsdate
(
ValID int,
DocID int,
value sql_variant
)
INSERT INTO #docsdate
SELECT 488,146,'30.10.2007' UNION ALL
SELECT 740,190,'31.03.2008' UNION ALL
SELECT 570,161,'31.10.2008' UNION ALL
SELECT 242,103,NULL UNION ALL
SELECT 248,104,NULL
SELECT * FROM #docsdate
WHERE value IS NULL
DROP TABLE #docsdate