MySQL 5.1 Inserting/Selecting Data in Wrong Order - mysql

I am trying to insert data into a table in sorted order, for later fast retrieval. I am using an ordinal column to specify the order of the data. Like so:
SET #ctr = -1;
insert into search_data (trans_id, ordinal)
select trans_id, #ctr:=#ctr+1
from transactions
order by created;
created is a datetime field.
Doing the select without the insert has the rows coming back in the correct order, but the ctr variable does not increment correctly. E.g.:
+---+----------+--------------+---------------------+
| 1 | trans_id | #ctr:=#ctr+1 | created |
+---+----------+--------------+---------------------+
| 1 | 131379 | 232 | 2011-10-17 12:27:09 |
| 1 | 131377 | 231 | 2011-10-17 12:24:30 |
| 1 | 131311 | 230 | 2011-10-16 23:44:12 |
| 1 | 131305 | 229 | 2011-10-16 21:57:35 |
| 1 | 129948 | 46 | 2011-10-10 13:24:58 |
| 1 | 129947 | 45 | 2011-10-10 13:24:58 |
| 1 | 129946 | 44 | 2011-10-10 13:24:58 |
| 1 | 129945 | 43 | 2011-10-10 13:24:58 |
| 1 | 129944 | 42 | 2011-10-10 13:24:58 |
This technique has worked for me in MySQL 5.0, 4.x and 3.x. But it doesn't work in 5.1.
It seems like the sort is being done after the variable is incremented, whereas previously the variable was incremented after the sort
Any thoughts?

Try subquery it:
select trans_id, #ctr:=#ctr+1
from ( select trans_id
from transactions
order by created, trans_id ) as t
asdfasdf

There is an apostrophe mark at the end of the initialisation of the ctr variable. Please check if it conforms to the syntax. I think the compiler is getting confused by that apostrophe mark.

Related

What exactly does EXISTS do in MySQL?

I read that the output of the subquery doesn't matter and only its existence matter. But, when I change the code in the subquery, why is my output changing?
These are the tables:
mysql> select * from boats;
+------+-----------+-------+
| bid | bname | color |
+------+-----------+-------+
| 101 | Interlake | blue |
| 102 | Interlake | red |
| 103 | Clipper | green |
| 104 | Marine | red |
+------+-----------+-------+
mysql> select * from sailors;
+------+---------+--------+------+
| sid | sname | rating | age |
+------+---------+--------+------+
| 22 | Dustin | 7 | 45 |
| 29 | Brutus | 1 | 33 |
| 31 | Lubber | 8 | 55.5 |
| 32 | Andy | 8 | 25.5 |
| 58 | Rusty | 10 | 35 |
| 64 | Horatio | 7 | 35 |
| 71 | Zorba | 10 | 16 |
| 74 | Horatio | 9 | 40 |
| 85 | Art | 3 | 25.5 |
| 95 | Bob | 3 | 63.5 |
+------+---------+--------+------+
10 rows in set (0.00 sec)
mysql> select * from reserves;
+------+------+------------+
| sid | bid | day |
+------+------+------------+
| 22 | 101 | 1998-10-10 |
| 22 | 102 | 1998-10-10 |
| 22 | 103 | 1998-10-08 |
| 22 | 104 | 1998-10-08 |
| 31 | 102 | 1998-11-10 |
| 31 | 103 | 1998-11-06 |
| 31 | 104 | 1998-11-12 |
| 64 | 101 | 1998-09-05 |
| 64 | 102 | 1998-09-08 |
| 74 | 103 | 1998-09-08 |
+------+------+------------+
select sname from sailors s where exists(select * from reserves r where r.bid=103);
+---------+
| sname |
+---------+
| Dustin |
| Brutus |
| Lubber |
| Andy |
| Rusty |
| Horatio |
| Zorba |
| Horatio |
| Art |
| Bob |
+---------+
10 rows in set (0.00 sec)
mysql> select sname from sailors s where exists(select * from reserves r where r.bid=103 and r.sid=s.sid);
+---------+
| sname |
+---------+
| Dustin |
| Lubber |
| Horatio |
+---------+
Also, I am not able to understand what r.sid=s.sid is doing here. All the sid in reserves are already from sailors table. Please someone explain it to me.
The EXISTS is a Boolean Operator which indicates that if there is ANY row in the sub-query you passed to it. When you execute this:
EXISTS(SELECT * FROM reserves r WHERE r.bid=103)
It will return TRUE after finding the FIRST row which has the condition bid = 103 in Reserves table. The first part of the query doesn't matter, it does not matter what you SELECT in Exists and MySQL engine will ignore it, just the WHERE clause is the part which makes the difference, you can use Exists even like this:
EXISTS(SELECT 1 FROM reserves r WHERE r.bid=103)
In the query above, nothing depends on the values in main query, nothing depends on Sailors table, and if there is ANY row in the Reserves table with bid = 103, then it always will return TRUE.
In the second sub-query with EXISTS, you have a different WHERE clause, and it depend on the value of the fields of the main Query, so it will have different result per each row:
EXISTS(SELECT * FROM reserves r WHERE r.bid=103 AND r.sid=s.sid)
In the above query, per each row in Sailors table, MySQL uses sid value to produce the WHERE condition of the sub-query in EXISTS operator, so it will returns TRUE for a row in Sailors table if there are ANY rows in Reserves table which has a bid = 103 and sid = Sailors.sid, and it will returns False for those that has not such a record in Reserves table, and finally you will get a different result
I think I got that. Exists is used to check if the subquery is existing for the main query. I didn't give any link for the main query and subquery in the first query.
For every name in sailors, independently, the subquery is existing. Hence, I got all the names. In the second query, I added s.sid=r.sid which links the main query and subquery. It checks if for a sname, if bid=103, and also, if s.sid=r.sid.
Please comment if I got that right.

mysql statement not working: DELETE FROM user_info WHERE username='t2';

Hi I'm trying to delete a row from mysql using the primary key. I've looked up a couple of examples and exactly followed the syntax, but mysql table is not getting affected.
I'm using:
DELETE FROM user_info WHERE username='t2';
mysql reponse:
Query OK, 0 rows affected (0.00 sec)
Screetshot of mysql table
seems you have single quote arount t2 in db 't2'
then try using
DELETE FROM user_info WHERE username="'t2'" ;
or
DELETE FROM user_info WHERE username like concat('%','t2', '%') ;
if you really have single quote saved in db arout t2 .. the you should avoid this kind of storage behaviour is really a bad practice store a value with (unuseful ) quote around
+----+------+------------+
| ID | NUM | CREATED |
+----+------+------------+
| 1 | 11 | 2018-01-01 |
| 2 | 22 | 2018-02-01 |
| 3 | 11 | 2018-03-01 |
| 4 | 44 | 2018-04-01 |
| 5 | 22 | 2018-05-01 |
| 6 | 44 | 2018-04-02 |
+----+------+------------+
DELETE from numbers where ID = 1;
+----+------+------------+
| ID | NUM | CREATED |
+----+------+------------+
| 2 | 22 | 2018-02-01 |
| 3 | 11 | 2018-03-01 |
| 4 | 44 | 2018-04-01 |
| 5 | 22 | 2018-05-01 |
| 6 | 44 | 2018-04-02 |
+----+------+------------+

How to find missing time value(s) in a given range in MySQL database?

Let's say I have a table like this:
| id | mtime |
...
| 101 | 12:00:00 |
| 102 | 12:01:00 |
| 103 | 12:03:00 |
| 104 | 12:07:00 |
| 105 | 12:08:00 |
| 106 | 13:00:00 |
...
Is there a way to query the table (range 12:00:00-13:00:00) to get a set with missing values like this:
| mtime |
| 12:02:00 |
| 12:04:00 |
| 12:05:00 |
| 12:06:00 |
| 12:09:00 |
| 12:10:00 |
...
| 12:59:00 |
or at least first empty occurance:
| mtime |
| 12:02:00 |
or last consecutive value, that breaks the chain:
| mtime |
| 12:01:00 |
I was thinking about using ADDTIME(time, '00:01:00') somewhere in the query but I can't figure it out. Right now I barely believe it's achievable without more complex coding and multiple queries, but I hope I'm missing something.
Generate a table (TABLE2) which have time of a full day (if u really need at any date),
and write your query like this
SELECT TABLE2.mtime FROM TABLE2
LEFT JOIN TABLE1 ON TABLE1.mtime = TABLE2.mtime
WHERE TABLE1.mtime IS NULL
also add condition for maximum and minimum time check, because TABLE2 have all dat times.

Reorder MySQL rows: move row "up"

I have a MySQL table where rows are inserted in a given order by the user. If the user then forgets to add a row and inserts it later it will come after the others that are already inserted, also when performing simple query. The order of insertion is the order I want the elements to be retreived. The table in question is a simple table resolving a many-to-many relationship with two IDs (recipe_id and ingredient_id).
mysql> select * from ingredient_in_recipe where recipe_id = 7;
+-----------+---------------+------+----------+------------+
| recipe_id | ingredient_id | unit | quantity | group_name |
+-----------+---------------+------+----------+------------+
| 7 | 71 | g | 300.00 | NULL |
| 7 | 34 | stk | 3.00 | NULL |
| 7 | 72 | stk | 1.00 | NULL |
| 7 | 73 | stk | 0.50 | NULL |
| 7 | 45 | stk | 6.00 | NULL |
| 7 | 74 | stk | 0.50 | NULL |
| 7 | 23 | g | 15.00 | NULL |
| 7 | 78 | ts | 2.00 | NULL |
| 7 | 75 | ts | 3.00 | NULL | <--- This is where I want the last element to be.
| 7 | 76 | ss | 1.00 | NULL |
| 7 | 77 | stk | 1.00 | NULL |
| 7 | 79 | g | 195.00 | NULL |
| 7 | 38 | ss | 5.00 | NULL | <--- This is inserted later. Should be "higher up".
+-----------+---------------+------+----------+------------+
13 rows in set (0.00 sec)
Is there a simple way to achieve this?
As pointed out by #C4ud3x and #Hanno Binder, there is no guarantee that MySQL returns the data in the same order as they were inserted. Normally, this is the case, but it is not a robust way to handle ordering of the data. Thus I solved the problem by adding a column order_id to be able to use the ORDER BY clause to ensure that the order will be maintained properly.
I found a good answer to a related question over at dba.stackexchange.com. The main point from the accepted answer there is:
If, on the other hand, you intend to rely on this order for anything, you must specify your desired order using ORDER BY. To do anything else is to set yourself up for unwelcome surprises.

user defined variable in MySQL query

I'm trying to create a data abstraction in SQL where I can choose the quarter I want to look at for my employee info. Right now I'm using the naming system Q1_P1_N for "Quarter 1 Project 1 name" and Q1_P1_W is "...project 1 weight." Employees can work on multiple projects.
So far what I have is:
CREATE PROCEDURE effort_lookup4(IN proj_name VARCHAR(20), IN quarter INT(1))
BEGIN
SET #Qx_P1_N = CONCAT('Q', quarter, '_P1_N');
SET #Qx_P2_N = CONCAT('Q', quarter, '_P2_N');
SET #Qx_P1_W = CONCAT('Q', quarter, '_P1_W');
SET #Qx_P2_W = CONCAT('Q', quarter, '_P2_W');
SET #var1 = (SELECT sum(#Qx_P1_W) FROM table_test WHERE #Qx_P1_N = proj_name);
SET #var2 = (SELECT sum(#Qx_P2_W) FROM table_test WHERE #Qx_P2_N = proj_name);
My problem is that whenever I call a query with #Qx_P1_N or #Qx_P1_W I'm not actually passing the correct query in and I can't figure out what I'm doing wrong. This should be pretty easy I'm just new to using SQL.
Here's an example of what the table looks like, except it carries on into Q2_P1_N and so on through the quarters:
+------+---------+---------+---------+---------+
| EMPID| Q1_P1_N | Q1_P2_N | Q1_P1_W | Q1_P2_W |
+------+---------+---------+---------+---------+
| 1000 | ProjA | ProjB | 0.50 | 0.50 |
| 1001 | ProjA | NULL | 1.00 | NULL |
| 1010 | ProjB | NULL | 1.00 | NULL |
| 1011 | ProjA | ProjB | 0.50 | 0.50 |
+------+---------+---------+---------+---------+
Thanks
To do what you want with your existing data structure requires that you use prepared statements (you build your desired SELECT statement as a string that you then PREPARE and EXECUTE).
However, you will probably find it easier to change your data structure:
+------+---------+---------+--------+
| EMPID| quarter | project | weight |
+------+---------+---------+--------+
| 1000 | 1 | A | 0.50 |
| 1000 | 1 | B | 0.50 |
| 1001 | 1 | A | 1.00 |
| 1010 | 1 | B | 1.00 |
| 1011 | 1 | A | 0.50 |
| 1011 | 1 | B | 0.50 |
+------+---------+---------+--------+
On your select statement you have a variable in the field that should be the column name in the table. You will need to switch the #Qx_P1_W for Q1_P1_W.