Update mysql database with subquery condition - mysql

I want to write 1 SQL syntax that will place current transaction in group. This transaction had to be done within last 60 seconds.
Grouping current transaction with other existing transactions is done by assigning group id number (GRID) that is copied from other transaction also performed within a last minute.
In other words:
purchase is done and SQL script will look for other purchases that has been done within last minute and if found it will take group number from found row and assign to current purchase, so in this case every purchase made within a minute will find itself in a group.
This is the update statement below I have composed
UPDATE TRANSACTIONS
SET GRID=(SELECT G FROM
(SELECT GRID AS G
FROM TRANSACTIONS
WHERE CUST_ID='123ID'
AND STAMP+60>UNIX_TIMESTAMP()
LIMIT 1)
AS t),
STAMP=UNIX_TIMESTAMP()
WHERE CUST_ID='123ID'
AND STAMP+60>UNIX_TIMESTAMP();
However this always returns number of updated rows, even if row which exists is only the one is due to be updated, or the other row that was found has no group number assigned yet. Which is obvious as it updates with whatever value was found in subquery. If nothing found it will update with empty value.
There are 2 solutions I am interested in:
I want this script to stop performing update (by condition) if found (from the sub query) value is basically empty.
or
I want to insert condition that if subquery returns empty value, the fix string of characters will be inserted instead.

After a while of exploring my issue I have come to solution.
The following MySQL syntax serves what I want.
Please note very interesting MySQL function IFNULL(). Can be very handy!
UPDATE TRANSACTIONS
SET GRID=(SELECT G FROM
(SELECT IFNULL(GRID, 'NO ID') AS G
FROM TRANSACTIONS
WHERE CUST_ID='123ID'
AND STAMP+60>UNIX_TIMESTAMP()
LIMIT 1)
AS t),
STAMP=UNIX_TIMESTAMP()
WHERE CUST_ID='123ID'
AND STAMP+60>UNIX_TIMESTAMP();

Related

MySQL - Updating a selection with iterative integers

Hello again internet nerds!
Technically I have solved this problem, but want to know if there is a more optimal route I should take...
I have a large table (~4m rows) that is a collection of data, segmented using int "chip." There are 6 segments of data, so Chip IDs 1 through 6.
Of these 6 segments, I need to assign an order integer, which needs to be iterative, as it represents the exact location of the data on said segment.
My solution is (was) this:
# set iterative
set #i:=0;
# init
update table set `order` = #i:=(#i+1) where chip = 1;
This works. But it is so slow it sometimes triggers a timeout error. I need to run it 6 times and it may be triggered on occasion by our application whenever necessary. Maybe it's just that I need to alot more time to MySQL settings to account for the slow query, or is there an optimal, simpler solution for this?
Thanks for the advice.
Edit:
I've found a solution that works accurately and takes ~50 seconds to complete.
I'm now using an ordered select statement paired in the update, using a generated join table that's iterating within a column.
See:
set #count:= 0;
update
table as target,
(select
(#count := #count+1) as row_num,
t.*
from table as t
where chip = 1
order by t.id asc) as table_with_iterative
set target.`order` = table_with_iterative.row_num
where target.id = table_with_iterative.id;
I think that if possible you should assign the sequence numbers as you are inserting the rows into the table for the very first time. Strictly speaking, an SQL database does not promise that rows will initially appear inside the table in the order of of the INSERT statements.
One possibility that occurs to me is to use an auto-increment field in this table, because this will express the order in which the rows were added. But the field-values for any given chip, although ascending, might not be consecutive and undoubtedly would not start at 1.
If you did need such a field, I think I'd define a separate field (default value: NULL) to hold it. Then, a very simple stored procedure could query the rows for a given chip (ORDER BY auto-increment number) and assign a 1-based consecutive sequential number to that separate field. (A slightly more elaborate query could identify all the lists that don't have those numbers yet, and number all of them at once.)
I've found a solution that works accurately and takes ~50 seconds to complete.
This handles the out-of-order updates I was experiencing.
I'm now using an ordered select statement paired in the update statement, using a generated join table that's iterating within a column row_num.
See:
set #count:= 0;
update
table as target,
(select
(#count := #count+1) as row_num,
t.*
from table as t
where chip = 1
order by t.id asc) as table_with_iterative
set target.`order` = table_with_iterative.row_num
where target.id = table_with_iterative.id;

SQL discrepancy using COUNT command

I am trying to do my first steps with SQL. Currently I am trying to analyse a database and stepped over a problem which I can't explain. Eventually someone could give me a hint.
I have a mySQL table ('cap851312') witch has 330.178 table rows. I already imported the table to Excel, and verified this number!
Every single row includes a field (column 'ID_MES_ANO') for the entries date. For the time being, all the date is uniquely set "201312".
Starting the following command, I would expect to see as a result the given number of rows, however the number which appears is 476.598.
SELECT movedb.cap851312.ID_MES_ANO, count(*)
FROM movedb.cap851312;
I already imported the file to Excel, and verified the number of lines. Indeed, it is 330.178!
How could I find out, what exactly is going wrong?
Update:
I've tried:
SELECT count(*) FROM movedb.cap851312
This returns as well 476.598.
As I am using workbench, I easily could confirm the numer of 330.178 table rows.
Update 2:
The Workbench Table Inspector confirms: "Table rows: 330178"
Solved - However unsure why:
I changed the statement to
SELECT count(ID_MES_ANO) FROM movedb.cap851512;
This time the result is 330178 !
COUNT(*) counts all rows.
COUNT(ID_MES_ANO) counts only rows for which ID_MES_ANO is not null.
So the difference between the two are the rows where ID_MES_ANO is null.
You can verify this with
SELECT count(*) FROM movedb.cap851512 WHERE ID_MES_ANO IS NULL;
By the way:
SELECT movedb.cap851312.ID_MES_ANO, count(*) FROM movedb.cap851312;
means: aggregate all rows to one single result row (by using the aggregate function COUNT without GROUP BY). This result row shows ID_MES_ANO and the number of all records. Standard SQL does not allow this, because you don't tell the DBMS which ID_MES_ANO of those hundreds of thousands of records to show. MySQL violates the standard here and simply picks one ID_MES_ANO arbitrarily from the rows.

MYSQL SET variable - update records with a number within specified range

My MYSQL statement doesn't seem to be working. I used to use this code from time to time to update the group sequencing in my table.
But for some reason, running this just changes all the records for "mach_group" fields to NULL. What it's supposed to do is update "mach_group" with a number between 1 and 11 within that criteria.
Can any of you spot whats going wrong?
SET #grp:=-1;
UPDATE mailing_new
SET `mach_group`=(#grp:=(#grp+1)%11)+1
WHERE machinery='1'
AND w='1'
AND (nw='1' or sw='1')
ORDER BY zip ASC

get last record in file

I have a table (rather ugly designed, but anyway), which consists only of strings. The worst is that there is a script which adds records time at time. Records will never be deleted.
I believe, that MySQL store records in a random access file, and I can get last or any other record using C language or something, since I know the max length of the record and I can find EOF.
When I do something like "SELECT * FROM table" in MySQL I get all the records in the right order - cause MySQL reads this file from the beginning to the end. I need only the last one(s).
Is there a way to get the LAST record (or records) using MySQL query only, without ORDER BY?
Well, I suppose I've found a solution here, so my current query is
SELECT
#i:=#i+1 AS iterator,
t.*
FROM
table t,
(SELECT #i:=0) i
ORDER BY
iterator DESC
LIMIT 5
If there's a better solution, please let me know!
The order is not guaranteed unless you use an ORDER BY. It just happens that the records you're getting back are sorted the way need them.
Here is the importance of keys (primary key for example).
You can make some modification in your table by adding a primary key column with auto_increment default value.
Then you can query
select * from your_table where id =(select max(id) from your_table);
and get the last inserted row.

MySQL - Counting rows in preparation for greatest-n-per-group not working?

Referring to SO and other sites have given me examples of how to use MySQL to create a 'greatest-n-per-group' query.
My variant on this would be to have a query that returns the first 3 rows of each category. As the basis for this I need to sort my data into a usable sequence and that is where my problems start. Running just the sequence query with row numbering shows that changes in category are mostly ignored. I should have 35 categories returning rows but only 5 do so.
My query:
set #c:=0;
set #a:=0;
SELECT IF(#c = tdg, #a:=#a+1, #a:=1) AS rownum, (#c:=tdg) ,
julian_day, sequence, complete, year, tdg
FROM tsd WHERE complete = 0
order by tdg, year, julian_day, sequence
Do I have a syntax mistake with this query?
OK, here's my comment as an answer:
The problem might be that your IF() assumes that all the rows that have common value in tdg should be sequentially in the table (i.e. no other rows in-between). ORDER is not done before the SELECT is done, but after all the rows have been fetched -> #a gets reset. Also, your reference page says you need the dummy column, so read those pages carefully.