How to find/insert data in missing sequence(auto increment) ID? - php

I have a table that contains
ID(P)(auto) NAME
-----------------------
1 Art
4 Bankie
6 Cara
The data sequence has 3 missing ID values: 2, 3 and 5.
This is my query:
$fname = $_POST['fname'];
mysql_query("INSERT INTO applicants ($fname) VALUES ('$fname')");
How can data be INSERTed in place of a missing ID value, in order to use all ID's.

What you're asking is not necessary for performance purposes, however to my knowledge there isn't a way to do this automatically. You would have to check for the missing ID ranges and assign them manually.
I would also recommend looking at the following post about SQL injection protection as it's a necessary step to maintaining a secure database connection. SQL Injection Prevention
Secondly, please do not use php's mysql_query() functions. These are deprecated and have been for some time now. MySQLi or PDO is recommended instead.

It's could be done using variable in sql query.
Let's say $name = $_POST['fname'];
Then you need insert query like this :
insert into yourtable(id,name)
select id-diff as new_id,'$name' from(
select id,id - (#x := #x + 1) as diff
from yourtable
join (select #x := 0) as t1
order by id asc
) as t2
where diff <> 0
limit 1

Related

How to handle multiple queries in PHP, including multiple TEMPORARY tables

This question is in relation to the answer of [another question][1] that I've posted a year ago.
Basically, I need to translate the answer in PHP and I don't even know where to start. Should I use 6 queries? Should I concatenate every query into 1 query? Should I use mysqli_multi_query?
I just need some advice, tips, and I will do the rest, I will do the research needed on how to achieve this in PHP.
This is the query that works perfectly and that I need to translate in PHP:
-- Query 1
CREATE TEMPORARY TABLE t (
ID INT AUTO_INCREMENT PRIMARY KEY
)
SELECT
w.work_id,
w.name wname,
r.sort_name rsortname,
CONCAT(r.seo_url, '.', r.recording_id) as rurl
FROM
WORK AS w
JOIN recording AS r ON w.work_id = r.work_id
JOIN `release` AS rl ON r.release_id = rl.release_id
WHERE
r.is_performer = 1
AND r.is_video = 0
ORDER BY
w.work_id,
- rl.released_year DESC,
- rl.released_month DESC,
- rl.released_day DESC,
rl.release_id;
-- Query 2
CREATE TEMPORARY TABLE x
SELECT
MIN(ID) AS ID
FROM
t
GROUP BY
work_id;
-- Query 3
SELECT
work_id,
wname,
rurl
FROM
x
JOIN t ON x.ID = t.ID
ORDER BY
rsortname;
-- Query 4, 5
DROP TEMPORARY TABLE t;
DROP TEMPORARY TABLE x;
Should I use 6 queries?
Yes, and if these queries depend on variable from PHP then you should use prepared statements to execute them.
Should I concatenate every query into 1 query?
Definitely not. They are not one query, they are all separate and you should execute them separately.
Should I use mysqli_multi_query?
Never! Forget that this function even exists. It is difficult to use and completely unnecessary. Just use prepared statements or command-line interface in MySQL for administrative tasks.

Execute > 1 SQL statement in single prepared statement

Alright so I'll try to explain it as simple as possible; consider that I have two database tables (MySQL Server / MariaDB, database-related tasks coded in procedural style in PHP using prepared statements):
in one, I have a column of datatype JSON, whose content corresponds to sth like {name1:info,name2:info}
In another one, I have simple non-json records, having a structure like:
name | status
------+--------
name1 | statusX
------+--------
name2 | statusY
My Goal: I need to retrieve the name2 from table 1), but I also need to retrieve the status of the person having that same name (which in this case is statusY). Note that, for the retrieval of name2, I cannot rely on indexes of the json object (name2 may be the first key of the json object).
How I would do it so far:
A) Get the name2 from table 1) in a first query, sanitize it, and
B) use it in the second query which then correctly retrieves the statusY
Both statements A) and B) are parametrized prepared sql statements, triggered by an AJAX Call at a regular interval (AJAX Polling).
Given that these database queries are thus executed frequently, I want them to be executed as fast as possible, and thus ideally reduce my two queries above to a single one. My problem: I need the result of statement A) to execute statement B), so I cannot summarize the two queries into a single prepared statement, as prepared statements cannot contain multiple sql statements. The best solution to reach what I want is create a stored procedure like:
SET #name = SELECT ..... FROM table_1; SELECT .... FROM table_2;
And then execute it as parametrized prepared statement; is that correct?
I'm not at all experienced with stored procedures in MySQL Server, didn't really need them yet, but they seem to be the only solution if you want to wrap > 1 sql statements into a single prepared statement. Is this assumption, and thus the conclusion that I gotta create a stored procedure to reach what I want, correct?
IMPORTANT NOTE: I don't know the name I need to query. From the two names of the json column of table 1), I only know the other name. In other words, I have one name of a person X, and I want to get the status of all the persons which have been associated with that person X in table 1), while the status of each person is listed in table 2), to avoid to have duplicate status storage in the DB. ATM, I retrieve the other names of each relation record from DB 1) by using a conditional statement saying sth like
UPDATE
See added answer below, got it working.
You can query JSON data type with MySQL (if version > 5.7), and thus you can simply do everything with a single query
Give this a try
SELECT t1.name1, t1.name2, t2.status
FROM
(
SELECT JSON_EXTRACT(your_json_column, "$.name1") AS name1,
JSON_EXTRACT(your_json_column, "$.name2") AS name2
FROM table1
WHERE JSON_EXTRACT(your_json_column, "$.name1") = 'info'
) t1
INNER JOIN table2 t2 ON t2.`name`=t1.name2
Adapt the name of your_json_column. Also I assumed that you wanted to search the name2 of a specific name1, thus my WHERE clause, remove it if it was a false assumption.
Okay got it working, pretty much thanks to the solution proposed by Thomas G and some hints of JNevill (cheers guys!):
SELECT t1.info1, t1.info2, t1.info3, t1.other_name, t2.status FROM (
SELECT
field1 AS info1,
field2 AS info2,
field3 AS info3,
CASE
WHEN JSON_VALUE(JSON_KEYS(json_names_column),"$[0]") = 'name1'
THEN JSON_VALUE(JSON_KEYS(json_names_column),"$[1]")
ELSE JSON_VALUE(JSON_KEYS(json_names_column),"$[0]")
END
AS other_name
FROM table1
WHERE id = 345
) t1 INNER JOIN table2 t2 ON t1.other_name = t2.name;
Note that I used JSON_VALUE(JSON_KEYS()) instead of JSON_EXTRACT, to only return the needed name as name data of t1, and because I don't know the name to retrieve before the query, so I cannot use the WHEREclause proposed by Thomas G.

How to improve Mysql database performance without changing the db structure

I have a database that is already in use and I have to improve the performance of the system that's using this database.
There are 2 major queries running about 1000 times in a loop and this queries have inner joins to 3 other tables each. This in turn is making the system very slow.
I tried actually to remove the query from the loop and fetch all the data only once and process it in PHP. But this is putting to much load on the memory (RAM) and the system is hanging if 2 or more clients try to use the system.
There is a lot of data in the tables even after removing the expired data .
I have attached the query below.
Can anyone help me with this issue ?
select * from inventory
where (region_id = 38 or region_id = -1)
and (tour_opp_id = 410 or tour_opp_id = -1)
and room_plan_id = 141 and meal_plan_id = 1 and bed_type_id = 1 and hotel_id = 1059
and FIND_IN_SET(supplier_code, 'QOA,QTE,QM,TEST,TEST1,MQE1,MQE3,PERR,QKT')
and ( ('2014-11-14' between from_date and to_date) )
order by hotel_id desc ,supplier_code desc, region_id desc,tour_opp_id desc,inventory.inventory_id desc
SELECT * ,pinfo.fri as pi_day_fri,pinfoadd.fri as pa_day_fri,pinfochld.fri as pc_day_fri
FROM `profit_markup`
inner join profit_markup_info as pinfo on pinfo.profit_id = profit_markup.profit_markup_id
inner join profit_markup_add_info as pinfoadd on pinfoadd.profit_id = profit_markup.profit_markup_id
inner join profit_markup_child_info as pinfochld on pinfochld.profit_id = profit_markup.profit_markup_id
where profit_markup.hotel_id = 1059 and (`booking_channel` = 1 or `booking_channel` = 2)
and (`rate_region` = -1 or `rate_region` = 128)
and ( ( period_from <= '2014-11-14' and period_to >= '2014-11-14' ) )
ORDER BY profit_markup.hotel_id DESC,supplier_code desc, rate_region desc,operators_list desc, profit_markup_id DESC
Since we have not seen your SHOW CREATE TABLES; and EXPLAIN EXTENDED plan it is hard to give you 1 answer
But generally speaking in regard to your query "BTW I re-wrote below"
SELECT
hotel_id, supplier_code, region_id, tour_opp_id, inventory_id
FROM
inventory
WHERE
region_id IN (38, -1)
AND tour_opp_id IN (410, -1)
AND room_plan_id IN (141, 1)
AND bed_type_id IN (1, 1059)
AND supplier_code IN ('QOA', 'QTE', 'QM', 'TEST', 'TEST1', 'MQE1', 'MQE3', 'PERR', 'QKT')
AND ('2014-11-14' BETWEEN from_date AND to_date )
ORDER BY
hotel_id DESC, supplier_code DESC, region_id DESC, tour_opp_id DESC, inventory_id DESC
Do not use * to get all the columns. You should list the column that you really need. Using * is just a lazy way of writing a query. limiting the columns will limit the data size that is being selected.
How often is the records in the inventory are being updates/inserted/delete? If not too often then you can use consider using SQL_CACHE. However, caching a query will cause you problems if you use it and the inventory table is updated very often. In addition, to use query cache you must check the value of query_cache_type on your server. SHOW GLOBAL VARIABLES LIKE 'query_cache_type';. If this is set to "0" then the cache feature is disabled and SQL_CACHE will be ignored. If it is set to 1 then the server will cache all queries unless you tell it not too using NO_SQL_CACHE. If the option is set to 2 then MySQL will cache the query only where SQL_CACHE clause is used. here is documentation about query_cache_type
If you have an index on those following column in this order it will help you (hotel_id, supplier_code, region_id, tour_opp_id, inventory_id)
ALTER TABLE inventory
ADD INDEX (hotel_id, supplier_code, region_id, tour_opp_id, inventory_id);
If possible increase sort_buffer_size on your server as most likely you issue here is that your are doing too much sorting.
As for the second query "BTW I re-wrote below"
SELECT
*, pinfo.fri as pi_day_fri,
pinfoadd.fri as pa_day_fri,
pinfochld.fri as pc_day_fri
FROM
profit_markup
INNER JOIN
profit_markup_info AS pinfo ON pinfo.profit_id = profit_markup.profit_markup_id
INNER JOIN
profit_markup_add_info AS pinfoadd ON pinfoadd.profit_id = profit_markup.profit_markup_id
INNER JOIN
profit_markup_child_info AS pinfochld ON pinfochld.profit_id = profit_markup.profit_markup_id
WHERE
profit_markup.hotel_id = 1059
AND booking_channel IN (1, 2)
AND rate_region IN (-1, 128)
AND period_from <= '2014-11-14'
AND period_to >= '2014-11-14'
ORDER BY
profit_markup.hotel_id DESC, supplier_code DESC, rate_region DESC,
operators_list DESC, profit_markup_id DESC
Again eliminate the use of * from your query
Make sure that the following columns have the same type/collation and same size. pinfo.profit_id, profit_markup.profit_markup_id, pinfoadd.profit_id, pinfochld.profit_id and each one have to have an index on every table. If the columns have different types then MySQL will have to convert the data every time to join the records. Even if you have index it will be slower. Also, if those column are characters type (ie. VARCHAR()) make sure they are of the CHAR() with a collation of latin1_general_ci as this will be faster for finding ID, but if you are using INT() even better.
Use the 3rd and 4th trick I listed for the previous query
Try using STRAIGHT_JOIN "you must know what your doing here or it will bite you!" Here is a good thread about this When to use STRAIGHT_JOIN with MySQL
I hope this helps.
For the first query, I am not sure if you can do much (assuming you have already indexed the fields you are ordering by) apart from replacing the * with column names (Don't expect this to increase the performance drastically).
For the second query, before you go through the loop and put in selection arguments, you could create a view with all the tables joined and ordered then make a prepared statement to select from the view and bind arguments in the loop.
Also, if your php server and the database server are in two different places, it is better if you did the selection through a stored procedure in the database.
(If nothing works out, then memcache is the way to go... Although I have personally never done this)
Here you have increase query performance not an database performance.
For both queries first check index is available on WHERE and ON(Join) clause columns, if index is missing then you have to add index to improve query performance.
Check explain plane before create index.
If possible show me the explain plane of both query that will help us.

Error in search from multi-tables by php and my sql

Now I'm trying to search in multi table but now my problem how to know which table you got the data ??
$query="(SELECT name FROM news WHERE name like '%$SER%' )
UNION ALL
(SELECT name FROM media WHERE name like '%$SER%') ";
$res=mysql_query($query);
while($row=mysql_fetch_array($res)){
echo $row[prog]."<br>";
}
mysql_num_rows($res);
How to know the result got from which table !!!
Add an extra column
select 1 as FromTable
UNION
select 2 as FromTable;
Anything from the second select will have 2 as $row["FromTable"]
You also NEED to read about SQL injections, and use the mysqli APIs instead ideally (? saves both parsing time, escaping time and the need to escape!)

SQL injection even when the variable is escaped [duplicate]

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 2 years ago.
The sql injection will work only when my query looks like below sample
SELECT * FROM login WHERE id = $my_id_va;
Assume if my query is
SELECT * FROM login WHERE id = $my_id_va ORDER BY id DESC
Than I will get following error
#1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'order by id desc' at line 1
So, this 1 or 1=1; SHOW TABLES will not work, correct?
My site was hacked successively many times.
I want one quick answer: When my query looks like the following one, what ways or which types of query can they use to hack my site?
SELECT * FROM login WHERE id = $my_id_va ORDER BY id DESC
What are the ways to execute the show table in the following query
SELECT * FROM login WHERE id = $my_id_va ORDER BY id DESC
I am also using escaping function to handle the query string values, like mysql_real_escape_string($my_id_va). Yes, obviously this for single related hack, but not sure.
Added some more
SELECT EventActuallyCharged, EventDate FROM tblevent WHERE EventDate between '2011-07-21 or 1=1; SHOW TABLES --' and '2011-07-31' ORDER BY EventDate DESC
but show table not worked
If you are using PHP5, use parametarized query, use PDO.
Int cast
If id is a number, you can int-cast your variable as well. Integers are safe to use:
$x = (int)$yourInputVar;
$s = "select * from Table where id = $x";
mysql_real_escape_string
If you want to pass a string, you can, and should, use mysql_real_escape_string, but this function escapes only those characters that are inside the string. You will still need to add quotes around the string, so:
$x = mysql_real_escape_string('hello');
$s = "select * from Table where id = $x";
.. will result in the query: select * from Table where id = hello. This is obiously not a valid query, since hello should be in quotes.
Change the query to:
$x = mysql_real_escape_string('hello');
$s = "select * from Table where id = '$x'";
.. and everything works fine. You add the quotes around, and mysql_real_escape_string takes care of special characters inside the string, if any.
Parameters
Another solution is to use parameterized queries. This can by done using MySQLi or PDO. The advantage is that you only tell your database where a variable should be inserted, and the database takes care of the escaping yourself.
It also may add a performance benefit, because these queries could be cached without their parameters, make a more efficient use of the query cache. This doesn't really work yet in current versions of MySQL, though.
You are right that 1 or 1=1; SHOW TABLES will give a syntax error but this will work:
1 or 1=1 --
The -- comments out the rest of the query.
In your case the value is an integer so instead of using mysql_real_escape_string you can use intval.
If you set $my_id_va to:
1 or 1=1; SHOW TABLES --
The -- will comment out the rest of the command, effectively terminating it.
I'm not sure what effect mysql_real_escape_string will have on the query. What you should be doing is parameterized queries.
1. First query somehow secured
$sql = sprintf('SELECT * FROM login WHERE id = %d ORDER BY id DESC', mysql_real_escape_string($my_id_va));
2. Second query somehow secured
$sql = sprintf("SELECT EventActuallyCharged, EventDate FROM tblevent WHERE EventDate BETWEEN '%s' AND '%s' ORDER BY EventDate DESC",
mysql_real_escape_string($start_date),
mysql_real_escape_string($end_date));
Read the docs about sprintf if you don't understand it.
However, as others have said, it would be very very secure if you would use parameterized queries with a class such as PDO or MySQLi.

Categories