Updating / inserting once and then exit - php

Hope some of you pros can help me out on this sql / php issue.
The short version:
I need to add members to a task-database. So I have memberlist, it loop through each member and runs below sql.
I need to run an SQL statement that is to exit after first update / execution where it hits the parameters. So I need some kind of return for each time the sql updates a field?
Pseudocode:
Update this column
condition 1
condition 2
after first execution exit
Current sql:
UPDATE calendar
SET spil1 = '$temp'
WHERE spil1 IS NOT NULL
AND
(dayname = 'Lørdag'
OR dayname = 'Søndag')
// now exit if the above is met and the sql update was executed.
So the problem is I cannot make it stop (tried limit, top etc)
How is this made with SQL? or is there a smart way to condition it in the PHP loop before executing the script?

if you are using any unique id put this code at the end of your query..
good luck.
AND unique_id IN ( SELECT unique_id FROM calendar order by unique_id ASC LIMIT 1 )

Do you have an id column in calendar? If yes use the following query (Not tested):
UPDATE calendar
SET spil1 = '$temp'
WHERE id =
(SELECT id FROM
(SELECT * FROM calendar
WHERE spil1 IS NOT NULL
AND
(dayname = 'Lørdag'
OR dayname = 'Søndag')
LIMIT 1)T)
What this query does, it brings the first record that applies to your condition, and then update that record the way you want it

I'm pretty sure you want to assign a different member to each NULL value in the calendar table. This is tricky. It requires enumerating the rows in each table for the join -- and assumes a unique id in the calendar table.
update calendar c join
(select c.*,
row_number() over (order by c2.pil1) as seqnum
from calendar c2
where c2.pil1 is not null and
c2.dayname in ('Lørdag', 'Søndag')
) c2
on c.calendar_id = c2.calendar_id join -- the unique id
(select ml.*,
row_number() over (order by ml.member_id) as seqnum
from memberlist ml
) ml
on ml.seqnum = c2.seqnum
set c.spil1 = ml.member_id;
I also suspect that you want the condition for the calendar table to be IS NULL rather than IS NOT NULL, but this is the logic you have in the question.

Related

Pagination Offset Issues - MySQL

I have an orders grid holding 1 million records. The page has pagination, sort and search options. So If the sort order is set by customer name with a search key and the page number is 1, it is working fine.
SELECT * FROM orders WHERE customer_name like '%Henry%' ORDER BY
customer_name desc limit 10 offset 0
It becomes a problem when the User clicks on the last page.
SELECT * FROM orders WHERE customer_name like '%Henry%' ORDER BY
customer_name desc limit 10 offset 100000
The above query takes forever to load. Index is set to the order id, customer name, date of order column.
I can use this solution https://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ if I don't have a non-primary key sort option, but in my case sorting is user selected. It will change from Order id, customer name, date of order etc.
Any help would be appreciated. Thanks.
Problem 1:
LIKE "%..." -- The leading wildcard requires a full scan of the data, or at least until it finds the 100000+10 rows. Even
... WHERE ... LIKE '%qzx%' ... LIMIT 10
is problematic, since there probably not 10 such names. So, a full scan of your million names.
... WHERE name LIKE 'James%' ...
will at least start in the middle of the table-- if there is an index starting with name. But still, the LIMIT and OFFSET might conspire to require reading the rest of the table.
Problem 2: (before you edited your Question!)
If you leave out the WHERE, do you really expect the user to page through a million names looking for something?
This is a UI problem.
If you have a million rows, and the output is ordered by Customer_name, that makes it easy to see the Aarons and the Zywickis, but not anyone else. How would you get to me (James)? Either you have 100K links and I am somewhere near the middle, or the poor user would have to press [Next] 'forever'.
My point is that the database is not the place to introduce efficiency.
In some other situations, it is meaningful to go to the [Next] (or [Prev]) page. In these situations, "remember where you left off", then use that to efficiently reach into the table. OFFSET is not efficient. More on Pagination
I use a special concept for this. First I have a table called pager. It contains an primary pager_id, and some values to identify a user (user_id,session_id), so that the pager data can't be stolen.
Then I have a second table called pager_filter. I consist of 3 ids:
pager_id int unsigned not NULL # id of table pager
order_id int unsigned not NULL # store the order here
reference_id int unsigned not NULL # reference into the data table
primary key(pager_id,order_id);
As first operation I select all records matching the filter rules from and insert them into pager_filter
DELETE FROM pager_filter WHERE pager_id = $PAGER_ID;
INSERT INTO pager_filter (pager_id,order_id,reference_id)
SELECT $PAGER_ID pager_id, ROW_NUMBER() order_id, data_id reference_id
FROM data_table
WHERE $CONDITIONS
ORDER BY $ORDERING
After filling the filter table you can use an inner join for pagination:
SELECT d.*
FROM pager_filter f
INNER JOIN data_table d ON d.data_id = f.reference id
WHERE f.pager_id = $PAGER_ID && f.order_id between 100000 and 100099
ORDER BY f.order_id
or
SELECT d.*
FROM pager_filter f
INNER JOIN data_table d ON d.data_id = f.reference id
WHERE f.pager_id = $PAGER_ID
ORDER BY f.order_id
LIMIT 100 OFFSET 100000
Hint: All code above is not tested pseudo code

Joining two mysql select statements where the second statement uses a column in first

I apologize in advance if this is super simple for some, but I'm not quite sure how to phrase the question to get relevant search results/answers to it. I'm also new to this. I thank you for your time in advance to look at my question.
I have two tables:
#1 - quote_requests . This is where all data is saved once a customer submits a quote request. This has a primary id called id.
#2 - quote_messages . Here are all the replies for all quote_requests. Basically a chat back and forth between the client and the sales rep. There's a column called quote_id that identifies the quote_requests' column id
So what I do in PHP is first run this statement
SELECT * FROM `quote_requests` WHERE `archived` = 0 AND `owner_id` != 0 AND `owner_id` = 64 ORDER BY `id` DESC
Then I go through the results with a while in PHP, with the purpose of seeing who was the last person that replied to the messages on that particular quote request: was it the client or the sales rep?
SELECT `reply_as`, `member_id` FROM `quote_messages` WHERE `quote_id` = :quote_id ORDER BY ID DESC LIMIT 1
Now obviously this is very bad because it takes 40 seconds for the page to process.
My question is:
How do I combine these two select statements into one considering that the second select statement is tied into the results of the first one. quote_id of quote_messages being the same as id of quote_requests
Thank you so much!
Hmmm . . . your method might be fine if there are not too many quote requests.
So, I might start just by using indexes on the existing queries:
quote_requests(owner_id, archived, id desc)
quote_messages(quote_id, id desc)
However, if you are doing a loop in PHP (which your question is not really explicit about), then you might want to run just one query in the database instead of a loop.
If I understand correctly the one query would look like:
SELECT qq.*
FROM (SELECT qm.quote_id, qm.reply_as, qm.member_id,
ROW_NUMBER() OVER (PARTITION BY qm.quote_id ORDER BY qm.id DESC) as seqnum
FROM quote_requests qr JOIN
quote_messages qm
ON qr.quote_id = qm.quote_id
WHERE qr.archived = 0 AND qr.owner_id = 64
) qq
WHERE seqnum = 1;
And for this you want the same indexes above.
There are 2 solutions for this to replace the while loop
Fetch for all quotes in a single query
SELECT `reply_as`, `member_id`
FROM `quote_messages`
WHERE id IN (
SELECT MAX(id)
FROM `quote_messages`
WHERE `quote_id` IN (:quote_ids)
GROUP BY ID
) AS a
adding 2 columns in quote_requests which will maintain the latest reply_as, member_id

How to find the next available integer in MySQL table using PHP

I know auto_increment is the way to go but I can not use auto_increment feature since the column in my table might repeat, its not unique. When I insert a new row to a table I need a way to find the next available spot to insert it.
For example table structure:
Primary Key = (ID, UserID)
ID UserID
3 6
3 1
1 3
Now when i do insert query i want to isert it at ID = 2 and not 4. With auto_increment it gives me 4
Is there a solution without using the loop in PHP? So far what i have is I fetch all rows into array and then find the next available digit in ID. Is it possible to do this without fetching all rows in PHP and just doing it on MySQL query ?
SELECT t1.id+1 AS MISSING_ID
FROM the_table AS t1
LEFT JOIN the_table AS t2 ON t1.id+1 = t2.id
WHERE t2.id IS NULL
ORDER BY t1.id LIMIT 1;
I made a fiddle: http://sqlfiddle.com/#!2/4d14d/2
No, it is not possible without processing the data. The preferred method to correct this issue is to adjust your table structure to support a unique, auto-incrementable field. Failing that, you will have to process the data (either in PHP or via an SQL statement) to find an open slot.
This should do the trick:
SELECT
min_table.ID+1 AS start,
MIN(max_table.ID) - 1 AS end
FROM
your_table AS min_table,
your_table AS max_table
WHERE
min_table.ID < max_table.ID
GROUP BY
min_table.ID
HAVING
start < MIN(max_table.ID)
The left hand column will return the first available spot in the sequence gap, and the second is the highest number in that particular gap.
Source: http://www.codediesel.com/mysql/sequence-gaps-in-mysql/
My workaround for not loaded project:
Suppose, you have questionset with question_id 's which belong to certain topic_id.
Suppose, user navigates and clicks "<Prev" "Next>" buttons to navigate questions.
You have only current id. Catching the direction of navigation, topic_id, question_id you can do a loop
do {
// query base, doing question_id++ or question_id-- depending on needed direction until you find next id within topic_id
} while( id!=null ) `
using incrementation or decrementation depending on direction of your move

UPDATE certain row in SELECTED items with Certain id

I need to Select a column with name song_number where id = 2 and then update the second row from the selected rows with 7 for example
what i think that the query i need is something like this but i can't get it work
UPDATE `song` SET `song_number`= 7 WHERE (SELECT `song_number` FROM `song` WHERE `id` = 2 LIMIT 1,1)
any help will be appreciated
edit: i think the problem is mainly in the database structure i made however i found a solution to what i need by making stored procedure http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html
so that i can save the selected items in a procedure and then update it
You have to identify which row you want to update. Identification means using a UNIQUE key or the PRIMARY key of the table.
The limitation of MySQL on UPDATE can be lifted by moving the condition from the WHERE to a JOIN:
UPDATE
song AS s
JOIN
( SELECT PK --- the Primary Key of the tba;e
FROM song
WHERE id = 2
ORDER BY ---whatever
LIMIT 1 OFFSET 1
) AS u
ON u.PK = s.PK
SET s.song_number= 7
If the PRIMARY KEY is id, then the above is useless of course. You are doing something wrong.
I doubt it is possible with one query and yet I see no reason in doing it in one query.
Why can't you just select and then update?
I think should be like this:
UPDATE `song` SET `song_number`= 7 WHERE `song_number` = (SELECT `song_number` FROM `song` WHERE `id` = 2 LIMIT 1,1);

Mysql in PHP - how to update only one row in table but with greatest id number

I am trying to update fields in my DB, but got stuck with such a simple problem: I want to update just one row in the table with the biggest id number. I would do something like that:
UPDATE table SET name='test_name' WHERE id = max(id)
Unfortunatelly it doesnt work. Any ideas?
Table Structure
id | name
---|------
1 | ghost
2 | fox
3 | ghost
I want to update only last row because ID number is the greatest one.
The use of MAX() is not possible at this position. But you can do this:
UPDATE table SET name='test_name' ORDER BY id DESC LIMIT 1;
For multiple table, as #Euthyphro question, use table.column.
The error indicates that column id is ambiguous.
Example :
UPDATE table1 as t1
LEFT JOIN table2 as t2
ON t2.id = t1.colref_t2
SET t1.name = nameref_t2
ORDER BY t1.id DESC
LIMIT 1
UPDATE table SET name='test_name' WHERE id = (SELECT max(id) FROM table)
This query will return an error as you can not do a SELECT subquery from the same table you're updating.
Try using this:
UPDATE table SET name='test_name' WHERE id = (
SELECT uid FROM (
SELECT MAX(id) FROM table AS t
) AS tmp
)
This creates a temporary table, which allows using same table for UPDATE and SELECT, but at the cost of performance.
I think iblue's method is probably your best bet; but another solution might be to set the result as a variable, then use that variable in your UPDATE statement.
SET #max = (SELECT max(`id`) FROM `table`);
UPDATE `table` SET `name` = "FOO" WHERE `id` = #max;
This could come in handy if you're expecting to be running multiple queries with the same ID, but its not really ideal to run two queries if you're only performing one update operation.
UPDATE table_NAME
SET COLUMN_NAME='COLUMN_VALUE'
ORDER BY ID
DESC LIMIT 1;
Because you can't use SELECT IN DELETE OR UPDATE CLAUSE.ORDER BY ID DESC LIMIT 1. This gives you ID's which have maximum value MAX(ID) like you tried to do. But MAX(ID) will not work.
Old Question, but for anyone coming across this you might also be able to do this:
UPDATE
`table_name` a
JOIN (SELECT MAX(`id`) AS `maxid` FROM `table_name`) b ON (b.`maxid` = a.`id`)
SET a.`name` = 'test_name';
We can update the record using max() function and maybe it will help for you.
UPDATE MainTable
SET [Date] = GETDATE()
where [ID] = (SELECT MAX([ID]) FROM MainTable)
It will work the perfect for me.
I have to update a table with consecutive numbers.
This is how i do.
UPDATE pos_facturaciondian fdu
SET fdu.idfacturacompra = '".$resultado["afectados"]."',
fdu.fechacreacion = '".$fechacreacion."'
WHERE idfacturaciondian =
(
SELECT min(idfacturaciondian) FROM
(
SELECT *
FROM pos_facturaciondian fds
WHERE fds.idfacturacompra = ''
ORDER BY fds.idfacturaciondian
) as idfacturaciondian
)
Using PHP I tend to do run a mysqli_num_rows then put the result into a variable, then do an UPDATE statement saying where ID = the newly created variable. Some people have posted there is no need to use LIMIT 1 on the end however I like to do this as it doesn't cause any trivial delay but could prevent any unforeseen actions from being taken.
If you have only just inserted the row you can use PHP's mysqli_insert_id function to return this id automatically to you without needing to run the mysqli_num_rows query.
Select the max id first, then update.
UPDATE table SET name='test_name' WHERE id = (SELECT max(id) FROM table)

Categories