execute long lasting php code with connection to database - php

I have to execute a PHP code just one time to make some changes in my database to have better tables. The code is too heavy and send more than 190000 queries to database (both select and insert).
Now the problem is when I execute it on the browser, form the result on the database and words that I've set to echo to check if it is going in correct way, I can find that it is executed partly. No error/warning/notice appears on the page.
I set max execute time and all the related settings to 1hour but it just take 30minuts and stop the for loop at once.
this is a sample of a part of my code:
for ($i=9;$i<=19909; $i++){
$j=0;
$select= "select synonym from synonym where x_=". $i ."";
//echo $select;
//echo "</br>";
$select_result= mysqli_query($connection,$select);
if (mysqli_num_rows($select_result)>0) {
$row = mysqli_fetch_assoc($select_result);
$arra = explode("،",$row["synonym"]);
}
while ($arra[$j]){
$text=trim($arra[$j]);
$search="select word from semiresult where word='". $text ."'";
$search_result= mysqli_query($connection,$search);
if (mysqli_num_rows($search_result)==0) {
$insert="insert into semiresult (x, word, synonym) values ('','". $text."','".$syn."')";
}elseif (mysqli_num_rows($search_result)>0){
$repeat="UPDATE semiresult SET synonym=CONCAT(synonym,'".$syn2."') where word like'".$arra[$j]."'";
$repeat_result=mysqli_query($connection,$repeat) or die ('request "Could not execute SQL query" '.$repeat);
}

With work you could avoid doing much of this in php. Whether it is worthwhile would depend on the data and table declares.
For example, assuming that word has a unique index on it in the semiresult table and that the synonym field has at most 1000 delimited fields you could do something like this (untested):-
INSERT INTO semiresult (x, word, synonym)
SELECT '',
'". $text."',
SUBSRTING_INDEX(SUBSRTING_INDEX(t1.synonym, '،', (hundreds.aCnt * 100 + tens.aCnt * 10 + units.aCnt + 1)), '،', -1)
FROM synonym t1
CROSS JOIN
(
SELECT 0 aCnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) AS units
CROSS JOIN
(
SELECT 0 aCnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) AS tens
CROSS JOIN
(
SELECT 0 aCnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) AS hundreds
WHERE t1.x_ BETWEEN 9 AND 19909
AND LENGTH(t1.synonym) - LENGTH(REPLACE(t1.synonym, '،', '')) > (hundreds.aCnt * 100 + tens.aCnt * 10 + units.aCnt)
ON DUPLICATE KEY UPDATE synonym=CONCAT(synonym, VALUES(synonym))

after all I solve it!!
After changing time limitations like max execute time and any other time limitations to two hours in php settings I add this line of code at the begining of my code then it execute until the end of the code.
set_time_limit(0);
This code was planned to execute one time only otherwise I have not do this changes.

Related

Mysql : last five records if having same value

I searched a lot and tried many queries but not getting satisfied answer. So like to ask.
I am looking for last 5 records from mysql table if having same value otherwise not.
Something like if col_n is having same value x from last 5 records then count otherwise not. But I am not able to figure out how to write query for this ?
SELECT count(col_n)
from track if(last five col_n = 'ok')
WHERE col_a = 'value1' AND col_b = 'value2'
enter mysql table records
Please try this:
SELECT p.*
FROM
( SELECT *
FROM demo ORDER by id DESC
LIMIT 5
) AS p
JOIN
( SELECT COUNT(*) AS cnt
FROM
( SELECT 1
FROM demo
LIMIT 5
) AS tmp
) AS c
ON c.cnt = 5 WHERE p.name='x'

PHP MYSQL General Error returned when using LIMIT [duplicate]

This question already has answers here:
Implement paging (skip / take) functionality with this query
(6 answers)
Closed 1 year ago.
I have this query with MySQL:
select * from table1 LIMIT 10,20
How can I do this with SQL Server?
Starting SQL SERVER 2005, you can do this...
USE AdventureWorks;
GO
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
FROM Sales.SalesOrderHeader
)
SELECT *
FROM OrderedOrders
WHERE RowNumber BETWEEN 10 AND 20;
or something like this for 2000 and below versions...
SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC
Starting with SQL SERVER 2012, you can use the OFFSET FETCH Clause:
USE AdventureWorks;
GO
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
ORDER BY SalesOrderID
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
GO
http://msdn.microsoft.com/en-us/library/ms188385(v=sql.110).aspx
This may not work correctly when the order by is not unique.
If the query is modified to ORDER BY OrderDate, the result set returned is not as expected.
This is how I limit the results in MS SQL Server 2012:
SELECT *
FROM table1
ORDER BY columnName
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
NOTE: OFFSET can only be used with or in tandem to ORDER BY.
To explain the code line OFFSET xx ROWS FETCH NEXT yy ROW ONLY
The xx is the record/row number you want to start pulling from in the table, i.e: If there are 40 records in table 1, the code above will start pulling from row 10.
The yy is the number of records/rows you want to pull from the table.
To build on the previous example: If table 1 has 40 records and you began pulling from row 10 and grab the NEXT set of 10 (yy).
That would mean, the code above will pull the records from table 1 starting at row 10 and ending at 20. Thus pulling rows 10 - 20.
Check out the link for more info on OFFSET
This is almost a duplicate of a question I asked in October:
Emulate MySQL LIMIT clause in Microsoft SQL Server 2000
If you're using Microsoft SQL Server 2000, there is no good solution. Most people have to resort to capturing the result of the query in a temporary table with a IDENTITY primary key. Then query against the primary key column using a BETWEEN condition.
If you're using Microsoft SQL Server 2005 or later, you have a ROW_NUMBER() function, so you can get the same result but avoid the temporary table.
SELECT t1.*
FROM (
SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
FROM ( ...original SQL query... ) t1
) t2
WHERE t2.row BETWEEN #offset+1 AND #offset+#count;
You can also write this as a common table expression as shown in #Leon Tayson's answer.
SELECT *
FROM (
SELECT TOP 20
t.*, ROW_NUMBER() OVER (ORDER BY field1) AS rn
FROM table1 t
ORDER BY
field1
) t
WHERE rn > 10
Syntactically MySQL LIMIT query is something like this:
SELECT * FROM table LIMIT OFFSET, ROW_COUNT
This can be translated into Microsoft SQL Server like
SELECT * FROM
(
SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum
FROM table
) a
WHERE rnum > OFFSET
Now your query select * from table1 LIMIT 10,20 will be like this:
SELECT * FROM
(
SELECT TOP 30 *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum
FROM table1
) a
WHERE rnum > 10
SELECT TOP 10 * FROM table;
Is the same as
SELECT * FROM table LIMIT 0,10;
Here's an article about implementing Limit in MsSQL Its a nice read, specially the comments.
This is one of the reasons I try to avoid using MS Server... but anyway. Sometimes you just don't have an option (yei! and I have to use an outdated version!!).
My suggestion is to create a virtual table:
From:
SELECT * FROM table
To:
CREATE VIEW v_table AS
SELECT ROW_NUMBER() OVER (ORDER BY table_key) AS row,* FROM table
Then just query:
SELECT * FROM v_table WHERE row BETWEEN 10 AND 20
If fields are added, or removed, "row" is updated automatically.
The main problem with this option is that ORDER BY is fixed. So if you want a different order, you would have to create another view.
UPDATE
There is another problem with this approach: if you try to filter your data, it won't work as expected. For example, if you do:
SELECT * FROM v_table WHERE field = 'test' AND row BETWEEN 10 AND 20
WHERE becomes limited to those data which are in the rows between 10 and 20 (instead of searching the whole dataset and limiting the output).
In SQL there's no LIMIT keyword exists. If you only need a limited number of rows you should use a TOP keyword which is similar to a LIMIT.
Must try. In below query, you can see group by, order by, Skip rows, and limit rows.
select emp_no , sum(salary_amount) from emp_salary
Group by emp_no
ORDER BY emp_no
OFFSET 5 ROWS -- Skip first 5
FETCH NEXT 10 ROWS ONLY; -- limit to retrieve next 10 row after skiping rows
Easy way
MYSQL:
SELECT 'filds' FROM 'table' WHERE 'where' LIMIT 'offset','per_page'
MSSQL:
SELECT 'filds' FROM 'table' WHERE 'where' ORDER BY 'any' OFFSET 'offset'
ROWS FETCH NEXT 'per_page' ROWS ONLY
ORDER BY is mandatory
This is a multi step approach that will work in SQL2000.
-- Create a temp table to hold the data
CREATE TABLE #foo(rowID int identity(1, 1), myOtherColumns)
INSERT INTO #foo (myColumns) SELECT myData order By MyCriteria
Select * FROM #foo where rowID > 10
SELECT
*
FROM
(
SELECT
top 20 -- ($a) number of records to show
*
FROM
(
SELECT
top 29 -- ($b) last record position
*
FROM
table -- replace this for table name (i.e. "Customer")
ORDER BY
2 ASC
) AS tbl1
ORDER BY
2 DESC
) AS tbl2
ORDER BY
2 ASC;
-- Examples:
-- Show 5 records from position 5:
-- $a = 5;
-- $b = (5 + 5) - 1
-- $b = 9;
-- Show 10 records from position 4:
-- $a = 10;
-- $b = (10 + 4) - 1
-- $b = 13;
-- To calculate $b:
-- $b = ($a + position) - 1
-- For the present exercise we need to:
-- Show 20 records from position 10:
-- $a = 20;
-- $b = (20 + 10) - 1
-- $b = 29;
If your ID is unique identifier type or your id in table is not sorted you must do like this below.
select * from
(select ROW_NUMBER() OVER (ORDER BY (select 0)) AS RowNumber,* from table1) a
where a.RowNumber between 2 and 5
The code will be
select * from limit 2,5
better use this in MSSQLExpress 2017.
SELECT * FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;
--Giving a Column [Count] and assigning every row a unique counting without ordering something then re select again where you can provide your limits.. :)
One of the possible way to get result as below , hope this will help.
declare #start int
declare #end int
SET #start = '5000'; -- 0 , 5000 ,
SET #end = '10000'; -- 5001, 10001
SELECT * FROM (
SELECT TABLE_NAME,TABLE_TYPE, ROW_NUMBER() OVER (ORDER BY TABLE_NAME) as row FROM information_schema.tables
) a WHERE a.row > #start and a.row <= #end
If i remember correctly (it's been a while since i dabbed with SQL Server) you may be able to use something like this: (2005 and up)
SELECT
*
,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20

Can I Count How Many Results Come From Each MySQL Select / Union

I have a query that follows this format:
(SELECT t.column1, t.column2
FROM table t
WHERE t.status = 1
LIMIT 10)
UNION
(SELECT t.column1, t.column2
FROM table t
WHERE t.status = 2
LIMIT 10)
The end result is that I need to have 20 rows. If the first SELECT statement can only find 9 rows with t.status = 1, then I would like the second SELECT statement to use LIMIT 11 instead of LIMIT 10
I am using PHP to write and run the query, but I am looking for something that will execute within MySQL so I can run it all as one query.
Any ideas would be greatly appreciated.
Add one more limit 'outside' with the total count and use the same for the limit of the 2-nd query.
(
SELECT t.column1, t.column2
FROM table t
WHERE t.status = 1
LIMIT 10 # 1/2 of total rows
)
UNION
(
SELECT t.column1, t.column2
FROM table t
WHERE t.status = 2
LIMIT 20 # total rows
)
LIMIT 20 # total rows

How to make a where clause where the value is an array from a previous sql query

I have a small list of data which is from an SQL database and uses mysql_fetch_array($query_run) to get it. This all works fine and I can echo out that data to double check it.
But where I want to use it is another SQL query, but where it doesn't equal it. My code at the moment only doesn't include one of the data items. So, I'm guessing you have to do something to let it know it's an array not just one piece of data?
Here's my code:
$query = "SELECT * FROM myFriends WHERE idPerson = '$loggedInUserId'";
$query_run = mysql_query($query);
while($row = mysql_fetch_array($query_run)) {
$idfriend = $row['idFriend'];
$queryFrirend = "SELECT * FROM perosn WHERE idPerson != '$idfriend'
Any help would be great!
Personally, I wouldn't bother with turning an array into a WHERE clause, if the set is returned from a MySQL query. Relational databases are built for this kind of thing.
A query with the familiar anti-join pattern will return the specified result:
SELECT p.*
FROM person p
LEFT
JOIN myFriends f
ON f.idFriend = p.idPerson
AND f.idPerson = '$loggedInUserId'
WHERE f.idFriend IS NULL
This says get all rows from the person table, and match to rows from the myFriends table. The WHERE clause says to exclude rows where a matching row was found, leaving only rows from person that didn't have a matching row returned from myFriends. With appropriate indexes, MySQL can blaze through that, without the overhead of sending a list of id values in a WHERE clause.
But, that doesn't really answer the question you asked.
The SQL you specified, including a list of idPerson values to be excluded, can be of several forms:
SELECT p.*
FROM person p
WHERE p.idPerson NOT IN (2,3,5,7,11,13,15,17,19)
or
SELECT p.*
FROM person p
WHERE p.idPerson <> 2
AND p.idPerson <> 3
AND p.idPerson <> 5
AND p.idPerson <> 7
AND p.idPerson <> 11
AND p.idPerson <> 13
AND p.idPerson <> 15
AND p.idPerson <> 17
or
SELECT p.*
FROM person p
WHERE NOT EXISTS
( SELECT 1
FROM ( SELECT 2 AS idPerson
UNION ALL SELECT 3
UNION ALL SELECT 5
UNION ALL SELECT 7
UNION ALL SELECT 9
UNION ALL SELECT 11
UNION ALL SELECT 13
UNION ALL SELECT 15
UNION ALL SELECT 17
UNION ALL SELECT 19
) f
WHERE f.idPerson = p.idPerson
)
or
SELECT p.*
FROM person p
LEFT
JOIN ( SELECT 2 AS idPerson
UNION ALL SELECT 3
UNION ALL SELECT 5
UNION ALL SELECT 7
UNION ALL SELECT 9
UNION ALL SELECT 11
UNION ALL SELECT 13
UNION ALL SELECT 15
UNION ALL SELECT 17
UNION ALL SELECT 19
) f
ON f.idPerson = p.idPerson
WHERE f.idPerson IS NULL
It's just a matter of looping through the rows in the result set, and using that value to format an appropriate SQL statement. The easiest approach (apart from aforementioned avoidance of having to run two separate queries to get the resultset you want), would be to build an array of the friendId column values. And then turn that array into a string of comma separated literals 2,3,5,7,9,11,13,17,19. Of course, you'd need to handle the edge case of no rows returned, because foo NOT IN () isn't valid SQL syntax.
If you want to build the statement on the fly, as you loop through the rows, you could do something like this:
$queryFrirend = "SELECT * FROM person WHERE 1=1";
while($row = mysql_fetch_array($query_run)) {
$queryFrirend .= " AND idPerson <> " . (int) $row['idFriend'];
}
$queryFrirend .= " ORDER BY idPerson";
echo "SQL=", $queryFrirend;
Though that's going to some ugly SQL. (I don't want to be around when the DBA comes hunting for you.)
You can't use arrays in SQL queries. You need to turn the array into a String of values separated by commas, and use IN().
SELECT * FROM perosn WHERE idPerson Not IN ('person1', 'person2')

Getting the values of a MySQL enum using only SQL

In a web application, I need to populate a <select> with all possible values of a MySQL enum.
When I execute either of:
SHOW COLUMNS FROM mytable LIKE 'mycolumn';
SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND COLUMN_NAME = 'mycolumn';
I always end up with enum('valueA','valueB','valueC').
I know I can parse it with PHP but can it be done using SQL only?
I need something like this:
+-----------------+
| values |
+-----------------+
| valueA |
| valueB |
| valueC |
+-----------------+
This is one of Chris Komlenic's 8 Reasons Why MySQL's ENUM Data Type Is Evil:
4. Getting a list of distinct ENUM members is a pain.
A very common need is to populate a select-box or drop down list with possible values from the database. Like this:
Select color:
[ select box ]
If these values are stored in a reference table named 'colors', all you need is: SELECT * FROM colors ...which can then be parsed out to dynamically generate the drop down list. You can add or change the colors in the reference table, and your sexy order forms will automatically be updated. Awesome.
Now consider the evil ENUM: how do you extract the member list? You could query the ENUM column in your table for DISTINCT values but that will only return values that are actually used and present in the table, not necessarily all possible values. You can query INFORMATION_SCHEMA and parse them out of the query result with a scripting language, but that's unnecessarily complicated. In fact, I don't know of any elegant, purely SQL way to extract the member list of an ENUM column.
While I would agree about not using enums most of the time, it is possible in a single SQL statement:-
SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING(COLUMN_TYPE, 7, LENGTH(COLUMN_TYPE) - 8), "','", 1 + units.i + tens.i * 10) , "','", -1)
FROM INFORMATION_SCHEMA.COLUMNS
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
WHERE TABLE_NAME = 'mytable'
AND COLUMN_NAME = 'mycolumn'
This will work for enums with up to 100 possible values
This is the simplest solution
$EnumColum = $mysqli->query(
$link,
"SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mrb_shipping_carriers' AND COLUMN_NAME = 'uspsServiceType'"
) or die("Error in " . ": " . __FILE__ . ": " . __LINE__);
$replace1 = preg_replace("/enum/", '',$EnumColum[0]['COLUMN_TYPE']);
$replace2 = preg_replace("/\(/", '',$replace1);
$replace3 = preg_replace("/\)/", '',$replace2);
$replace4 = preg_replace("/\'/", '',$replace3);
$newArray = explode(',',$replace4);
foreach($newArray as $value){
echo $value . "\n<br>";
}

Categories