SQL Getting position in database WHERE from array - php

I'm working on a scoreboard which separates from global, region and country. I got global and country working. Here's my code to get the number per country:
$euCountries = array('AL', 'AD', 'AM', 'AT', 'BY', etc....);
if (in_array($CountryCode, $euCountries)) { $region = 'EU'; }
$countryRankSql = "SELECT name, FIND_IN_SET(xp, (
SELECT GROUP_CONCAT(xp ORDER BY xp DESC)
FROM users WHERE countrycode = :CountryCode ) ) AS rank
FROM users WHERE id = :id";
$countryRankGet = $db->prepare($countryRankSql);
$countryRankGet->execute(array(
':CountryCode' => $CountryCode,
':id' => $id,
));
$countryRank = $countryRankGet->fetch()['rank'];
Now I would like to do the same, but WHERE are multiple CountryCodes from an array (for example $euCountries). So basically the same as the country sql only where WHERE countrycode = :CountryCode
is an array of countries.
How am I going to do this?

Take that same string, without converting to an array, and use it in your select statement:
SELECT name, FIND_IN_SET(xp, (SELECT GROUP_CONCAT(xp ORDER BY xp DESC) FROM users WHERE countrycode in ($euCountries) ) ) AS rank FROM users WHERE id = :id
That's pretty much it.

Related

MERGE INTO USING from dual (ORA-00923 FROM keyword not found where expected)

My query below was working, I swear... now suddenly, it's dead, outputting 'ORA-00923 FROM keyword not found where expected'.. I cannot understand why... I have tried various linters and syntax checkers; I am simply iterating through array data and pushing to a oracle table/row - adding a new entry if table_id is not found, and updating table_id if it is found. What am I missing?
Data coming in is perfect too.. what am I doing incorrectly..
$fd = json_decode($df, true);
foreach ($fd as $key=>$data) {
var_dump($data);
$sql = "MERGE INTO app.table a
using (SELECT '${data[0]}' table_id,
'${data[1]}' fac_ident,
'${data[2]}' lg_name,
'${data[3]}' basic_tp,
'${data[4]}' catc_vd,
'${data[5]}' address,
'${data[6]}' assoc_city,
'${data[7]}' latitude,
'${data[8]}' longitude,
'${data[9]}' assoc_cnty,
'${data[10]}' assoc_st,
'${data[11]}' time_zone,
FROM dual) p
ON ( a.table_id = p.table_id )
WHEN matched THEN
UPDATE SET a.fac_ident = p.fac_ident,
a.lg_name = p.lg_name,
a.basic_tp = p.basic_tp,
a.catc_vd = p.catc_vd,
a.address = p.address,
a.assoc_city = p.assoc_city,
a.latitude = p.latitude,
a.longitude = p.longitude,
a.assoc_cnty = p.assoc_cnty,
a.assoc_st = p.assoc_st,
a.time_zone = p.time_zone,
WHEN NOT matched THEN
INSERT (table_id,
fac_ident,
lg_name,
basic_tp,
catc_vd,
address,
assoc_city,
latitude,
longitude,
assoc_cnty,
assoc_st,
time_zone)
VALUES (p.table_id,
p.fac_ident,
p.lg_name,
p.basic_tp,
p.catc_vd,
p.address,
p.assoc_city,
p.latitude,
p.longitude,
p.assoc_cnty,
p.assoc_st,
p.time_zone)";
..........
If your data contains a single quote then you are doing the equivalent of trying to perform an SQL injection attack.
Don't use variable parsing ${data[0]}; instead create your query using bind variables and pass in your data properly so you are not vulnerable to SQL injection attacks.
For example:
If you have the table:
CREATE TABLE table_name (
table_id VARCHAR2(100),
fac_ident VARCHAR2(100)
)
And you have a table_id of 1 and a fac_ident of 2 then your merge would be:
MERGE INTO table_name a
USING (
SELECT '1' table_id,
'2' fac_ident
FROM dual
) p
ON ( a.table_id = p.table_id )
WHEN matched THEN
UPDATE SET a.fac_ident = p.fac_ident
WHEN NOT matched THEN
INSERT (table_id, fac_ident )
VALUES (p.table_id, p.fac_ident );
This works.
However, if fac_ident has the value This value has a 'quote' inside it. then your query is:
MERGE INTO table_name a
USING (
SELECT '1' table_id,
'This value has a 'quote' inside it.' fac_ident
FROM dual
) p
ON ( a.table_id = p.table_id )
WHEN matched THEN
UPDATE SET a.fac_ident = p.fac_ident
WHEN NOT matched THEN
INSERT (table_id, fac_ident )
VALUES (p.table_id, p.fac_ident );
And fails with:
ORA-00923: FROM keyword not found where expected
More insidious, is if fac_indent has the value '||(SELECT secret_column FROM secret_data WHERE ROWNUM = 1)||' and then your query becomes:
MERGE INTO table_name a
USING (
SELECT '1' table_id,
''||(SELECT secret_column FROM secret_data WHERE ROWNUM = 1)||'' fac_ident
FROM dual
) p
ON ( a.table_id = p.table_id )
WHEN matched THEN
UPDATE SET a.fac_ident = p.fac_ident
WHEN NOT matched THEN
INSERT (table_id, fac_ident )
VALUES (p.table_id, p.fac_ident );
And, if the table SECRET_DATA exists and has the column SECRET_COLUMN then your query won't fail and users can start to do unexpected things with your query. Please don't let them do this and use best practice of formulating your queries using bind variables rather than string concatenation.
db<>fiddle here

Laravel Raw SQL Queries with named bindings for multiple occurences

I am using DB facade and select method to run raw SQL queries with bindings. Just need to know can we do have multiple parameters with the same name in the query and replace that by providing only 1 binding with parameter name.
e.g.
$sql = "SELECT students.id, students.name FROM students
where students.student_id = :student_id
where added_on = ( SELECT MAX( added_on ) AS newdate
FROM students WHERE student_id = :student_id)"
return DB::select($sql, [
'student_id' => 1
]);
note: it might possible that I do not have to use student_id twice in this query. It just an example.
The purpose is to know if we can achieve this.
I don't believe its possible, it's not ideal, but I generally do something like:
$sql = "SELECT students.id, students.name FROM students
where students.student_id = :student_id_1
where added_on = ( SELECT MAX( added_on ) AS newdate
FROM students WHERE student_id = :student_id_2)"
$student_id = 1;
return DB::select($sql, [
'student_id_1' => $student_id,
'student_id_2' => $student_id
]);

PHP PDO Select ANY value does not return anything

$sql = $baglanti->prepare("
SELECT inv_id, item_id
FROM inventory
WHERE item_id = ANY (
SELECT item_id
FROM inventory
WHERE :uzunwhere
) AND item_color = ANY (
SELECT item_color
FROM inventory
WHERE :uzunwhere
) AND item_quality = ANY (
SELECT item_quality
FROM inventory
WHERE :uzunwhere
) AND item_location = :loc
AND (character_id = :cid OR :cid = :owner)
");
$sql->execute(array(
':uzunwhere' => $whereKosul,
':loc' => $mekanid,
':cid' => $charID,
':owner' => $ishome['place_ownerID']
));
$bulunanlar = $sql->fetchAll(/*PDO::FETCH_ASSOC*/);
$sayi = $sql->rowCount();
echo $sayi;
When i catch the result, $sayi shows me 0. I am not sure about that is there any query syntax like that "ANY" in PHP?
I also tried this code in MySQL workbench via query runner. There is no problem in there.
$uzunWhere is a variable which can be changeable with my if statement above the code. Here is the example:
$uzunWhere = "inv_id = 111 OR inv_id = 95"
SQL parameters cannot be expressions. Use a parameter in place of a single scalar value like a numeric constant, a quoted string constant, or a date constant.
You cannot use a parameter for any other part of the query, like an expression, or a table or column identifier, or an SQL keyword, or a list of values (unless you use a separate parameter per value in the list).
For your $uzunWhere variable, you have to interpolate it into the string without using a query parameter.
$sql = $baglanti->prepare("
SELECT inv_id, item_id
FROM inventory
WHERE item_id = ANY (
SELECT item_id
FROM inventory
WHERE $uzunWhere
) AND item_color = ANY (
SELECT item_color
FROM inventory
WHERE $uzunWhere
) AND item_quality = ANY (
SELECT item_quality
FROM inventory
WHERE $uzunWhere
) AND item_location = :loc
AND (character_id = :cid OR :cid = :owner)
");
This means you must take other precautions in the code that defines $uzunWhere, to make sure it does not introduce SQL injection risks.

Multiple SQL queries and FOREACH - Can be JOINED to one?

I am trying to pull a list of Events, also seeing which members have paid for the Events. I then want to see if they are on the committee, to see if they have admin permissions.
I have successfully done this, using three SQL queries, then using three foreach loops to build the Array.
I am SURE this can be done with one SQL query and one foreach loop, however I have not yet mastered the JOIN technique.
I am using Expression Engine, Codeigniter Active Record, I will display to you the SQL output and also what my current EE functions look like.
THANKS FOR THE HELP! :D
SQL to select ALL events which are active
SELECT `id` as event_ID, `name` as event_name, `description` as event_description
FROM (`events`)
WHERE `events_category_id` = '1'
AND `active` = 1
ORDER BY `name` asc
EE CODE to achieve this:
$query = $this->theDb->select('id as event_ID, name as event_name, description as event_description')
->order_by("name", "asc")
->get_where('events', array('event_category_id'=>$event_type,'active'=>1));
**
SQL to find what EVENT IDs the user has paid for
**
SELECT DISTINCT `products`.`event_ID` as joinedID
FROM (`transactions_items`)
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`
JOIN `events` ON `events`.`id` = `products`.`event_ID`
WHERE `transactions`.`member_id` = 27500
AND `events`.`active` = 1
AND `event_category_id` = '1'
ORDER BY `events`.`name` asc
EE CODE to achieve this
$query = $this->theDb->select('products.event_ID as joinedID')
->distinct()
->order_by("events.name", "asc")
->join('transactions', 'transactions.id = transactions_items.id')
->join('products', 'products.id = transactions_items.product_id')
->join('events', 'events.id = products.event_ID')
->get_where('transactions_items', array('transactions.member_id' => $memberID, 'events.active' => 1,'activity_category_id'=>$activity_type));
SQL to find ADMIN rights
SELECT `events`.`id` as event_ID, `admins`.`admin_role_id` as role_id, `admins_roles`.`name` as role_description
FROM (`admins`)
JOIN `admins_roles` ON `admins`.`admin_role_id` = `admins_roles`.`id`
JOIN `events` ON `events`.`id` = `admins`.`event_ID`
WHERE `admins`.`member_id` = 27500
AND `events`.`active` = 1
EE CODE to achieve this
$query = $this->theDb->select('events.id as event_ID, admins.admin_role_id as role_id, admins_roles.name as role_description')
->join('admins_roles', 'admins.admin_role_id = admins_roles.id')
->join('events', 'events.id = admins.event_ID')
->get_where('admins', array('admins.member_id' => $memberID, 'events.active' => 1));
FOR EACH LOOPS
// Create list of Events setting defaults
foreach($events_list as $row)
{
$combinedEvents[$row->event_ID] = array(
'eventID' => $row->event_ID,
'eventName' => $row->event_name,
'eventDescription' => $row->event_description,
'isJoined' => 0,
'roleID' => 0,
'roleDescription' => "",
);
}
// Add Committee roles
foreach($admin_list as $row)
{
$combinedEvents[$row->event_ID]['roleID'] = $row->role_id;
$combinedEvents[$row->event_ID]['roleDescription'] = $row->role_description;
}
// Add Transactions
foreach($transaction_list as $row)
{
$combinedEvents[$row->joinedID]['isJoined'] = 1;
}
I don't quite understand the FOREACH part because I've never touched PHP - but you should be able to solve the multiple SQL queires using the ;with clause. I have created an example in response to another question here and here. Is this what you're looking for?

Make a select query from two table with where clause.

I have two variables $code and $name. $code probably have tutor's code or institute's code and$name also probably have tutor's name or institute's name.
This is the way the names come to $code and $name
// Check Tutor or Institute
if ( $tutorCode && $tutorName) {
$code = $tutorCode;
$name = $tutorName;
} elseif ( $instituteCode && $instituteName) {
$code = $instituteCode;
$name = $instituteName;
}
My problem is I need to get email address from contact table according to this $code and $name. Need to check two table tutor and institute which belong to code and name.
tutor and institute table have contact_id and contact table also have contact_id.
tutor table have tutor_code and tutor_name.
institute table have institute_code and institute_name
I tried something like this. but can't check in both tables.
$q = "SELECT email FROM tutor
WHERE tutor_code = $code AND tutor_name = $name"
Hope someone will help me.
Thank you.
you can UNION both tables
SELECT email, code, name
FROM
(
SELECT email, tutor_code as code, tutor_name as Name FROM tutor
UNION ALL
SELECT email, institute_code as code, institute_name as Name FROM institute
) sub
WHERE code = $code AND
name = '$name'
or
SELECT s.*, c.*
FROM
(
SELECT contact_ID,
tutor_code as code,
tutor_name as Name,
'TUTOR' sourceTbl
FROM tutor
WHERE tutor_code = $code AND
tutor_name = '$name'
UNION ALL
SELECT contact_ID,
institute_code as code,
institute_name as Name,
'INSTITUTE' sourceTbl
FROM institute
WHERE institute_code = $code AND
institute_name = '$name'
) s
INNER JOIN contact c
ON s.contact_ID = c.contact_ID
keep it mind that it will return duplicate record if both records exists on both table because of specifying ALL in the UNION. If you want to get only unique records, remove ALL.
You should read up on using joins in mysql.
http://dev.mysql.com/doc/refman/5.0/en/join.html
And for both the institute and tutor part, you could use a UNION or joins.
In your case it would look something like this:
$q = "SELECT c.email
FROM contact c
LEFT JOIN tutor t on t.contact_id = c.contact_id
LEFT JOIN institute i on i.contact_id = c.contact_id
WHERE
(
(t.tutor_code = $code AND t.tutor_name = $name) OR
(i.institute_code = $code AND i.institute_name = $name) OR
)";
to look at your query i am noticing that there is issue for $code and $name values.
you need to add $code and $name inside double quote or single quotes.

Categories