I believe this is causing anywhere from a 5 minute to 20 minute delay depending on the number of records. I need to translate it into a LEFT JOIN but need some help getting it there.
qry_arr = array(':bill_type' => "INT");
$sql = "update ".$billing_table." c set c.bill_type = :bill_type";
$sql .= " WHERE NOT EXISTS (SELECT s.abbreviation FROM state s WHERE s.abbreviation = c.out_location)";
$sql .= " and c.out_location != 'UNKNOWN' and c.out_location != ''";
UPDATE $billing_table c
LEFT JOIN state s ON s.abbreviation = c.out_location
SET c.bill_type = :bill_type
WHERE s.abbreviation IS NULL
AND c.out_location NOT IN ('UNKNOWN', '')
This is essentially the same as the syntax for a SELECT for the rows that don't match. See Return row only if value doesn't exist. Just replace SELECT ... FROM with UPDATE, and insert the SET clause before WHERE.
Make sure you have indexes on out_location and abbreviation.
Related
This database has worked fine for two years, now it's getting the following error? Can someone explain this issue and suggest a way to resolve this?
Error Number: 1104
The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay
Code:
select
salary_tb.*, order_tb.order_no,
daily_target_tb.customer as customer_name,
jobs_tb.job as job_name
from
salary_tb
left join
order_tb on salary_tb.order_id = order_tb.id
left join
daily_target_tb on order_tb.id = daily_target_tb.order_id
left join
jobs_tb on salary_tb.job_id = jobs_tb.id
where
salary_tb.id > 0
and salary_tb.isDeleted = 0
and salary_tb.employee_id = '1'
group by
salary_tb.id
Filename: models/SalaryModel.php
Line Number: 22
The issue is your query is either returning huge number of rows which is more than value set for MAX_JOIN_SIZE configuration or your SQL_BIG_SELECTS is set to 0 which will not allow you to run queries which take too long to return a result. You can do one/all of the following 3 things :
1.SET SQL_BIG_SELECTS=1;
2.MAX_JOIN_SIZE= (More than the no of rows returned by the join statement)
Refine your query so that it returns appropriate values within the set parameters and in less time.(Using Indexing, Returning less no. of rows).
Current Query
function get_rows($where)
{
$sql =
"select salary_tb.*, order_tb.order_no, daily_target_tb.customer as customer_name, jobs_tb.job as job_name
from salary_tb
left join order_tb on salary_tb.order_id = order_tb.id
left join daily_target_tb on order_tb.id = daily_target_tb.order_id
left join jobs_tb on salary_tb.job_id = jobs_tb.id
where salary_tb.id > 0";
if($where != ""){
$sql .= $where;
}
$query =# $this->db->query('SET SQL_BIG_SELECTS=1');
$this->db->query($sql);
return $query->result_array();
}
I want to update the last row in a mysql table
UPDATE logend
SET endsecs = endsecs+'$moretime'
WHERE id = (SELECT id FROM logend ORDER BY id DESC LIMIT 1)
But it doesn't work, because of this error:
ERROR 1093 (HY000): You can't specify target table 'logend' for update in FROM clause
In MySql you can't use the updated table in a subquery the way you do it.
You would get the error:
You can't specify target table 'logend' for update in FROM clause
What you can do is an UPDATE with ORDER BY and LIMIT:
$sql = "UPDATE logend SET endsecs=endsecs+'$moretime' ORDER BY id DESC LIMIT 1";
Can't you just get the max(id) and update that?
$sql = "UPDATE logend SET endsecs=endsecs+'$moretime' WHERE id = (
SELECT id FROM (
SELECT MAX(id) FROM logend) AS id
)";
Here's another solution: a self-join, to find the row for which no other row has a greater id.
Also, you should really not interpolate POST inputs directly into your SQL statement, because that exposes you to SQL injection problems. Use a query parameter instead.
$moretime = $_POST['moretime'];
$sql = "
UPDATE logend AS l1
LEFT OUTER JOIN logend AS l2 ON l1.id < l2.id
SET l1.endsecs = l1.endsecs + ?
WHERE l2.id IS NULL";
$stmt = $mysqli->prepare($sql);
if (!$stmt) {
trigger_error($mysqli->error);
die($mysqli->error);
}
$stmt->bind_param("s", $moretime);
$ok = $stmt->execute();
if (!$ok) {
trigger_error($stmt->error);
die($stmt->error);
}
I want to DELETE data OR UPDATE data in MYSQL. such that if column message_deleted_by is found in a string IN() then the query should delete rows where the WHERE clause(filtering) is true ELSE the query should update message_table column message_deleted_by with some data ....ALL IN THE SAME QUERY
if this can be achieved please help.
I'v tried and tried but it output errors.
$token = mysqli_real_escape_string($dbc_conn,encode64(getsecreteToken($_POST["token"])));
$mid = mysqli_real_escape_string($dbc_conn,$_POST["mid"]);
$rid = mysqli_real_escape_string($dbc_conn,$_POST["rid"]);
$sid = mysqli_real_escape_string($dbc_conn,$_POST["sid"]);
$group = implode(",",array($rid,$sid));
$IsLoggIn = '2';
$SQL = "
IF(
SELECT message_deleted_by AS mdb FROM $message_tatable
WHERE (
m.sender_id='$IsLoggIn' AND m.recipient_id='$rid'
) AND
m.token='$token' AND m.id='$mid'
) mdb IN($group) THEN
DELETE m,mf
FROM $message_tatable m
LEFT JOIN $message_files_tb mf ON
m.token=mf.token
WHERE (
m.sender_id='$IsLoggIn' AND m.recipient_id='$rid'
) AND
m.token='$token' AND m.id='$mid';
ELSE
UPDATE $message_tatable SET message_deleted_by='$IsLoggIn'
WHERE (
m.sender_id='$IsLoggIn' AND m.recipient_id='$rid'
) AND
m.token='$token' AND m.id='$mid';
END IF;
";
//QUERY database
$query = mysqli_query($dbc_conn,$SQL);
die(mysqli_error($dbc_conn));
Try this,
UPDATE $message_tatable m
LEFT JOIN $message_files_tb mf
ON m.token=mf.token
SET m=NULL,
mf=NULL
WHERE m OR mf=SELECT message_deleted_by FROM $message_tatable IN($group)
AND m.sender_id='$IsLoggIn' AND m.recipient_id='$rid'
AND m.token='$token' AND m.id='$mid'
An input and script in index.php
<input type="text" class="filter" id="frClientName" name="cl_name">
<script>
$(".filter").on('change keydown keyup', function(){
var clname;
clname = document.getElementById("frClientName").value;
$("#spravaContent").load("php/search_results/sprava.php?cl_name=" + clname;
});
</script>
php/search_results/sprava.php
$clname = '';
if ( isset ( $_GET['cl_name'] ) ) {
$clname = $_GET['cl_name'];
}
$sql = ("
SELECT * FROM `db`.`table`
WHERE cl_full_name LIKE '%".$_GET['cl_name']."%'
");
How can I use WHERE clause right and only if variable isn't empty?
Thank you for some direction.
EDIT:
$sql = ("
SELECT * FROM `db`.`table`
ORDER BY {$oby} {$ohow}
WHERE cl_full_name LIKE '%".$_GET['cl_name']."%'
OR '' = '".$_GET['cl_name']."'
LIMIT $start_sprava,$per_page_sprava
");
It's a bit hacky, but I've handled situations like this with a CASE statement. You evaluate your argument and if it doesn't meet the condition you require, you use an obviously true statement like 1=1 which has the net effect of keeping that part of the WHERE clause from participating in filtering the result set.
SELECT *
FROM `db`.`table`
WHERE CASE WHEN TRIM('".$_GET['cl_name']."') IS NOT NULL THEN cl_full_name LIKE '%".$_GET['cl_name']."%'
ELSE 1=1
END
ORDER BY {$oby} {$ohow}
LIMIT {$start_sprava}, {$per_page_sprava}
;
Don't forget to police your inputs so you don't wind up with a Little Bobby Tables problem. Also, the ORDER BY and LIMIT clauses generally come after the WHERE clause.
Make the where clause work whether set or not.
Assuming your app language returns the text "null" if variable is not set:
"SELECT * FROM `db`.`table`
WHERE cl_full_name LIKE '%".$_GET['cl_name']."%'
OR 'null' = '".$_GET['cl_name']."'"
I have relationships that might not necessarily exist (they could be optional i.e. null); for example, a image may not have an address so it may be null.
I am unsure how to not return all null values.
Is there some condition I can put in place on the join that says if the address is null don't do a join and don't return all the null columns?
SELECT im.title, im.alias_title, im.description, im.main_image, im.hits,
im.show_comment, im.created_on, im.date_taken, im.account_type_id,
c.make, c.model, ad.address_line_1, ad.address_line_2,
spc.state_province_county, tvc.town_village_city, co.country,
ge.latitude, ge.longitude, ge.zoom, ge.yaw, ge.pitch,
us.first_name, us.surname, us.user_set_online, ut.username,
ut.account_type_id, aty.`type`, ufy.realname, ufy.location,
ufy.location, ufy.account_type_id
FROM image im
INNER JOIN user us
ON im.user_id = us.id
LEFT JOIN user_type ut
ON us.id = ut.user_id
LEFT JOIN user_flickr_youtube ufy
ON ut.id = ufy.user_type_id
LEFT JOIN account_type aty
ON ut.account_type_id =aty.id
LEFT JOIN address ad
ON im.address_id = ad.id
LEFT JOIN state_province_county spc
ON ad.state_province_county_id = spc.id
LEFT JOIN town_village_city tvc
ON ad.town_village_city_id =tvc.id
LEFT JOIN country co
ON ad.country_id =co.id
LEFT JOIN geolocation ge
ON im.geolocation_id = ge.id
LEFT JOIN camera c
ON im.camera_id = c.id
WHERE im.alias_title = 'test'
AND im.approved = 'Yes'
AND im.visible = '1'
LIMIT 1;
Is there some condition i can put in place on the join that says if the address is null dont do a join and dont bring me back all the null columns
Yes; you can run a JOIN instead of a LEFT JOIN. But that won't simply exclude the address if it is NULL, it will ignore the whole row altogether.
Usually this kind of situation is either handled by supplying a default value, possibly empty, for example directly in MySQL
SELECT
...COALESCE(ad.address_line_1,'(no address)') AS address_line_1,
COALESCE(ad.address_line_2,'') AS address_line_2, ...
or it is handled by the application:
if row['address_line_1']:
result = result + ("<td class=\"address\">%s</td>" % ( row['address_line_1'] ))
...
This also because a query could potentially return not one record, but several, and of these, some might have a NULL colum and some might not.
UPDATE
There is a way, but it's likely to make milk go sour in cows fifty miles downrange.
This is a proof of concept, on a MUCH smaller query and table, and takes advantage of the possibility of dynamically building a query.
First of all we have our query WHERE condition, here represented by "id = 1". We want to have the name column if the name column is not NULL.
SELECT #address := COALESCE(MIN(',name'),'') FROM client WHERE name IS NOT NULL AND id = 1;
This will return an empty string if the selected column is NULL. Otherwise it will return a comma and the name of that column.
This is the statement that in your case will be humongous, given your query. It contains the same WHERE as before, without the request that the name be NULL. And the field list is now dynamic.
SELECT #string := CONCAT('SELECT id', #address, ' FROM client WHERE id = 1');
Except that #string is, well, a string. To execute it as a query we do
PREPARE query FROM #string;
EXECUTE query;
DEALLOCATE PREPARE query;
How this might interact with your application, I do not dare fathom. I have tried an implementation in PHP on an expendable VM :-), cycling between the values of 1 and 3 (one row has a NULL name, one hasn't).
<?php
// Connect to this VM's local DB
mysql_connect('localhost','root','') or die("Cannot connect");
mysql_select_db('test');
foreach(array(1, 3) as $id)
{
mysql_query("SELECT #address := COALESCE(MIN(',name'),'') FROM client WHERE name IS NOT NULL AND id = $id;");
mysql_query("SELECT #string := CONCAT('SELECT id', #address, ' FROM client WHERE id = ', $id);");
mysql_query("PREPARE query FROM #string;");
$exec = mysql_query("EXECUTE query;");
while($tuple = mysql_fetch_assoc($exec))
{
print implode(" | ", $tuple) . "\n";
}
mysql_query("DEALLOCATE PREPARE query;");
}
?>
The answer seems to indicate it's working:
1 | Rossi
3
(I wouldn't have been surprised if it returned something like 'Ia! Cthulhu fhtagn!').