How are the correct mysql script? - mysql

i have a mysql's script as follow as:
SET #waktu = NULL;
SELECT username,
IF (#username = username,
IFNULL(TIMEDIFF(waktu,#waktu),0), #waktu:=waktu +
NULL + LEAST(0,#username := username)) selisih_waktu, #waktu:=`waktu` as time
FROM mdl_temporer_log2 WHERE rolename = 'Student'
ORDER BY waktu
After, i run that script, it will show as follow as:
username | selisih_waktu | time
-----------|---------------|--------------
aq | null | 05:55:07
aq | null | 05:55:09
megi | null | 05:55:37
megi | null | 05:55:40
megi | null | 05:55:45
but, when I run it a second time, that script will show as follow as:
username | selisih_waktu | time
-----------|---------------|--------------
aq | 0 | 05:55:07
aq | 00:00:02 | 05:55:09
megi | null | 05:55:37
megi | 00:00:03 | 05:55:40
megi | 00:00:03 | 05:55:45
I want to get output from that script as follow as:
username | selisih_waktu | time
-----------|---------------|--------------
aq | null | 05:55:07
aq | 00:00:02 | 05:55:09
megi | null | 05:55:37
megi | 00:00:03 | 05:55:40
megi | 00:00:03 | 05:55:45
So, i'm confused, are that script wrong or right? and if that script are wrong, how are the correct scripts?

The problem is here:
...#waktu:=waktu + NULL + LEAST...
Why are you adding NULL here? NULL is not zero or anything, it is unknown.
Anything + unknown = unknown
Just remove the + NULL.
EDIT:
Now that I read a bit more about it, this here
LEAST(0,#username := username))
doesn't make sense to me either. LEAST() returns the smallest argument, but you're comparing apples and oranges. The second parameter is just assigning a row value to a variable.
You should explain, what your query should do (with words, not just with tables), otherwise this question doesn't make much sense and is unanswerable.

Related

Unexpected NOT EQUAL TO NULL comparison in MySQL [duplicate]

This question already has answers here:
What's the difference between " = null" and " IS NULL"?
(4 answers)
Closed 5 years ago.
I have below table in MySQL.
city_data
+------+-----------+-------------+
| id | city_code | city_name |
+------+-----------+-------------+
| 4830 | BHR | Bharatpur |
| 4831 | KEP | Nepalgunj |
| 4833 | OHS | Sohar |
| 4834 | NULL | Shirdi |
+------+-----------+-------------+
and below query.
select id,city_code,city_name from city_data where city_code != 'BHR';
I was expecting 3 rows.
| 4831 | KEP | Nepalgunj |
| 4833 | OHS | Sohar |
| 4834 | NULL | Shirdi |
+------+-----------+-------------+
But getting only 2 rows.
| 4831 | KEP | Nepalgunj |
| 4833 | OHS | Sohar |
+------+-----------+-------------+
I am not able to understand why the row
| 4834 | NULL | Shirdi |
Not includes in the result of my query. The where condition(NULL != 'BHR') should have been passed.
Please, someone, help to clear the doubt.
According to MySQL Reference Manual, section 3.3.4.6: Working with NULL values the following is why:
Because the result of any arithmetic comparison with NULL is also
NULL, you cannot obtain any meaningful results from such comparisons.
In MySQL, 0 or NULL means false and anything else means true. The
default truth value from a boolean operation is 1.
This means that NULL != 'BHR' will evaluate to NULL, which in turn will mean false to MySQL. In order for the query to work as you want, you have to append OR city_code IS NULL to your query.
You cannot compare null values with !=, because it is null, use IS NULL predicate instead:
select id,city_code,city_name
from city_data
where city_code != 'BHR' OR city_code IS NULL;
It is not possible to test for NULL values with comparison operators, such as =, <, or <>. Therefore query is confusing and NULL record is being ignored. for more info go to https://www.w3schools.com/sql/sql_null_values.asp

MySQL query executes fine, but returns (false) empty result set when using != NULL?

I have the following result set, that I'm trying to drill down
+----+---------+---------------+---------------------+----------------------+---------------+-----------+------------------+------------------+
| id | auth_id | trusts_number | buy_sell_actions_id | corporate_actions_id | fx_actions_id | submitted | created_at | updated_at |
+----+---------+---------------+---------------------+----------------------+---------------+-----------+------------------+------------------+
| 2 | 6 | N100723 | 2 | NULL | NULL | 0 | 08/05/2015 11:30 | 08/05/2015 15:32 |
| 5 | 6 | N100723 | NULL | NULL | 1 | 0 | 08/05/2015 15:10 | 08/05/2015 15:10 |
| 6 | 6 | N100723 | NULL | NULL | 2 | 1 | 08/05/2015 15:12 | 08/05/2015 15:41 |
+----+---------+---------------+---------------------+----------------------+---------------+-----------+------------------+------------------+
This result set is generated with the query
SELECT * FROM actions WHERE auth_id = 6 AND trusts_number = 'N100723'
I also want to get rid of any field with fx_actions is NULL, so I change the query to
SELECT * FROM actions WHERE auth_id = 6 AND trusts_number = 'N100723' AND fx_actions_id != NULL
However this returns an empty result set. I've never used "negative" query parameters in MySQL before, so I'm not sure if they should take on a different syntax or what?
Any help would be much appreciated.
Normal comparison operators don't work well with NULL. Both Something = NULL and Something != NULL will return 'unknown', which causes the row to be omitted in the result. Use the special operators IS NULL and IS NOT NULL instead:
SELECT * FROM actions
WHERE auth_id = 6
AND trusts_number = 'N100723'
AND fx_actions_id IS NOT NULL
Wikipedia on NULL and its background
Because null isn't a value, you should use IS NOT NULL

SQL matching column with another in same table, IN statement not working

I'm trying to make an SQL query. I'm still new to SQL, maybe someone could give me some direction, or let me know if this is even possible.
Please note I have read up on IN, ALL, INNER JOIN etc and I still cannot get the proper query. I have tried to find the solution for hours.
These are my table columns:
+-----------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+-------+
| route | varchar(100) | NO | PRI | NULL | |
| stopID | varchar(5) | NO | PRI | NULL | |
| stopName | varchar(100) | NO | | NULL | |
| Latitude | float(10,6) | YES | | NULL | |
| Longitude | float(10,6) | YES | | NULL | |
| timeList | varchar(1000) | NO | | NULL | |
| day | varchar(5) | NO | PRI | NULL | |
+-----------+---------------+------+-----+---------+-------+
I need the stopId's and stopNames where the stopName matches another stopName with a different stopID AND the day='Week' (Otherwise a total of 3 results will come back since there are Week, Sat, Sun days.).
| 16 | 1639 | MYUNIQUESTOPNAME | 43.514000 | -80.199600 | (a really long list of times) | Week |
| 5 | 0530 | MYUNIQUESTOPNAME | 43.514000 | -80.199600 | (a really long list of times) | Week |
SELECT stopID,stopName FROM Routes WHERE stopName='MYUNIQUESTOPNAME' AND day='Week';
+--------+---------------------------+
| stopID | stopName |
+--------+---------------------------+
| 1612 | MYUNIQUESTOPNAME |
| 1639 | MYUNIQUESTOPNAME |
| 0530 | MYUNIQUESTOPNAME |
+--------+---------------------------+
Gives me what I want, but that's only for one stop, and doing it this way, I would have to do it manually. There's a lot of stops.
Secondly, I would then want all the id's and names that have NO matches (are unique to the bus route).
SELECT stopID,stopName FROM Routes WHERE stopName IN (SELECT stopName FROM Routes WHERE day='Week') AND day='Week';
The above DOES NOT GIVE ME WHAT I WANT. All my searching implies that it is though... What am I doing incorrectly...?
mysql version is 5.5.41-0+wheezy1
Do a self join on the table (routes) on the column (stopName) and then get all the results where day=week and stopIds are not same. This would give you the answer to the first query
Select unq.stopId, unq.stopName from Routes unq join Routes other on other.stopName=unq.stopName where unq.stopId!= other.stopId and unq.day = 'Week'
For the second one where you want only those which are unique, do a group by on stop name and pick the records where grouping results in only one record
Select unq.stopId, unq.stopName from Routes unq group by unq.stopName having count(*) = 1
If you want a list of stops where the list is small ad you can use IN:
SELECT stopID,stopName
FROM Routes
WHERE stopName IN ('MYUNIQUESTOPNAME', 'ANOTHERNAME', 'AThirdNAME') AND day='Week';
To get a list of stops where the stopName exists more than once for a week day:
SELECT stopID,stopName
FROM Routes
WHERE stopName IN
(SELECT DISTINCT stopName
FROM Routes
WHERE day = 'Week'
GROUP BY stopName
HAVING COUNT(stopName) > 1)
AND day='Week';
With the query you are running you will return all stops as the nested query will always contain the stop from the outer query.
Use the following to stop this from happening.
SELECT stopID,stopName AS s1
FROM Routes
WHERE stopName IN (SELECT stopName AS s2
FROM Routes
WHERE day='Week'
AND s1.stopID <> s2.stopID)
AND day='Week';

Troubles conceptualizing a query

I have a 'Course' table and an 'Event' table.
I would like to have all the courses that actually take place, i.e. they are not cancelled by an event.
I have done this by a simple request for all the course and a script analysis (basically some loops), but this request take a time that I believe too long. I think what I want is possible in one query and no loops to optimize this request.
Here are the details :
'Course' c have the fields 'date', 'duration' and a many to many relation with the 'Grade' table
'Event' e have the fields 'begin', 'end', 'break' and a many to many relation with the 'Grade' table
A course is cancelled by an event if they occur at the same time and if the event is a break (e.break = 1)
A course is cancelled by an event if all the grades of the course are in the events that occurs at the same time (many events can occurs, I have to sum up the grades of these events and compare them to the grades of the courses). This is the part I'm doing with a loop, I have some trouble to conceptualize that.
Any help is welcome,
Thanks in advance,
PS : I'm using mysql
EDIT : Tables details
-Course
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | datetime | NO | | NULL | |
| duration | time | NO | | NULL | |
| type | int(11) | NO | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
+-------+---------------------+----------+------+
| id | date | duration | type |
+-------+---------------------+----------+------+
| 1 | 2013-12-10 10:00:00 | 02:00:00 | 0 |
| 2 | 2013-12-11 10:00:00 | 02:00:00 | 0 |
+-------+---------------------+----------+------+
-Event
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| begin | datetime | NO | | NULL | |
| end | datetime | YES | | NULL | |
| break | tinyint(1) | NO | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
+----+---------------------+---------------------+-------+
| id | begin | end | break |
+----+---------------------+---------------------+-------+
| 1 | 2013-12-10 00:00:00 | 2013-12-11 23:59:00 | 1 |
+----+---------------------+---------------------+-------+
-course_grade
+-----------+----------+
| course_id | grade_id |
+-----------+----------+
| 1 | 66 |
| 2 | 65 |
| 2 | 66 |
+-----------+----------+
-event_grade
+----------+----------+
| grade_id | event_id |
+----------+----------+
| 66 | 1 |
+----------+----------+
So here, only the course 2 should appear, because course 1 has only one grade, and this grade has an event.
I like riddles, this is a nice one, has many solutions, I think
As you say 'Any help is welcome', I give an answer altough its not the solution (and it does not fit into a comment)
I dont know, if you just want (A) the naked statement (over and out), or if you want (B) to understand how to get to the solution, I take (B)
I start with 'what would I change' before starting about the solution:
you are mixing date,datetime,start,end and duration, try to use only one logic (if it is your model ofcourse) ie.
an event/course has a start and an end time (or start/duration)
duration should (IMHO) not be a time
try to find a smallest timeslice for events/course (are there 1 sec events? or is a granularity of 5' (ie. 10:00, 10:05, 10:10 ans so on) a valid compromise?
My solution, a prgmatic one not academic
(sounds funny, but does work good in a simillar prob I had see annotation)
Create a table (T_TIME_OF_DAY) having all from 00:00, 00:05, .. 23:55
Create a Table (T_DAYS) in a valid and usefull range (a year?)
the carthesian product - call it points in time - (ie. select date, time from T_DAYS,T_TIME_OF_DAY no condition) of them (days x times) 300*24*12 ~ 100.000 rows if you need to look at a whole year (and 5' are ok for you) - thats not much and no prob
the next step is to join the curses fitting to your points in time (and the rows are down to <<100.000)
if you next join these with your events (again using point in time) you should get what you want.
simplyfied quarters of a day:
12 12 12 12 12 12 12 12
08 09 10 11 12 13 14 15
|...|...|...|...|...|...|...|...
grade 65 (C).............2..................
grade 66 (C).........1...2..................
grade 65 (E)................................
grade 66 (e)........1111..................
(annotation: I use this logic to calculate the availabillity of services regarding to their downtimes per Month / Year, and could use the already in timeslices prepared data for display)
(second answer, because it is a totaly different and mor3 standard aproach)
I made an SQLFiddle for you
so what to do:
and thats the a solution:
step one (in mind) select course,grades (lets call them C)
step two (in mind) select events, grades (lets call them E)
and - tada -
select all from C where there a no rows in E that have the same grade and the same date(somehow) and eventtype='break'
so your solution:
select
id, date start_time, date+duration end_time, grade_id
from Course c join course_grade cg on c.id=cg.course_id
where not exists (
select grade_id, begin start_time, end end_time
from event_grade eg join event e on eg.event_id=e.id
where
eg.grade_id=cg.grade_id
and e.break=1
and
(
(e.begin<=c.date and e.end >=c.date+c.duration)
or e.begin between c.date and c.date+c.duration
or e.end between c.date and c.date+c.duration
)
)
I did take no attention to optimize here

mysql - How to filter results without specifying the columns

It might sound silly but Im just curious.
I have a table named posts:
+----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(50) | YES | | NULL | |
| body | text | YES | | NULL | |
| created | datetime | YES | | NULL | |
| modified | datetime | YES | | NULL | |
+----------+------------------+------+-----+---------+----------------+
The values:
+----+-----------------------+----------------------------------------+---------------------+---------------------+
| id | title | body | created | modified |
+----+-----------------------+----------------------------------------+---------------------+---------------------+
| 2 | A title once again!!! | And the post body follows. Tralalalala | 2013-06-03 13:13:44 | 2013-06-05 09:36:51 |
| 3 | Title strikes back | This is really exciting! Not. | 2013-06-03 13:13:46 | NULL |
| 11 | Tomcat | Tommy boy!!! FFF | 2013-06-04 16:33:22 | 2013-06-04 16:48:40 |
| 12 | FFD | dsfdsf | 2013-06-04 16:48:56 | 2013-06-04 16:55:50 |
| 13 | fdf | dfdsf | 2013-06-04 16:57:47 | 2013-06-05 09:36:54 |
| 14 | GGD | dsfdsf | 2013-06-04 17:02:33 | 2013-06-04 17:02:33 |
| 15 | GG# | dsfdsfff322 | 2013-06-05 09:36:20 | 2013-06-05 09:36:28 |
+----+-----------------------+----------------------------------------+---------------------+---------------------+
Let's say I want to search for row that has the value Th (not case sensitive) regardless of the FIELD. This is like making a quick search function.
Normally I would do something like : SELECT * FROM posts WHERE title LIKE '%Th%' OR body LIKE '%Th%'
I did not include the other fields because obviously they are not gonna accept those values.
I wanna know if there's a shortcut to this? Like SELECT * FROM posts LIKE '%Th%'.
Please advise. Thanks.
Using plain old SQL you need to specify all the column names you wish to include.
If you want more search-box-like behavior, I'd suggest looking at MySQL's fulltext functions; see:
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
The SQL language is based on the presumption of the schema being known. Thus, there is no "search any column" type of functionality. How would it work against non-text columns? What about columns of different collations? Aside from the language not having a feature, specifying the columns expresses your intent to the next developer and that as much as anything should be an overriding consideration.
Other answers have covered that you need to specify all the columns. Here is an alternative formulation that is a bit shorter:
SELECT *
FROM posts
WHERE concat(title, ' ', body) LIKE '%Th%'
If you are looking for an exact match, then you can do:
select *
from posts
where 'Th' in (title, body)
No there is no shortcut for using a where clause. and specifying the columns. Otherwise the query engine can never know what to filter and what column to filter unless you specify them in the where clause.
If you want a custom shortcut - you can write a function which takes a single parameter (the search string) and returns the required fields.
I'm afraid there isn't.
Not sure what your use case is... does this alternative approach work for your use case?
mysql -u{user} -p{password} -h{hostname} {database_name} -B -e "{query}" | grep "{search_string}"
It connects to the database and runs the specified query, returns query results in new lines, fields separated by tab stop. Then use Unix utility grep to filter returned rows.