Laravel Raw SQL Queries with named bindings for multiple occurences - php

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
]);

Related

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.

Yii2 translating findBySql query to QueryBuilder query

I have the following query using findbysql:
$query = Users::findBySql('select a.user_id, a.last_name,a.first_name, a.emp_id, ar.role_id from auth_users a, auth_user_roles AR, AUTH_USER_DEPTS AD, DEPARTMENTS D
where AD.DEPT_ID = D.DEPT_ID AND AR.USER_ID = AD.USER_ID and a.user_id = ar.user_id
AND D.DEPT_GROUP_ID = :dept_group_id AND (ACCESS_END_DATE > SYSDATE OR ACCESS_END_DATE IS NULL)
UNION
SELECT DISTINCT a.user_id, a.last_name, a.first_name, a.emp_id, NULL AS role_id FROM auth_users a, AUTH_USER_ROLES AR, AUTH_USER_DEPTS AD, DEPARTMENTS D
WHERE AD.DEPT_ID = D.DEPT_ID AND AR.USER_ID = AD.USER_ID and a.user_id = ar.user_id
AND D.DEPT_GROUP_ID = :dept_group_id AND
AR.ACCESS_END_DATE < SYSDATE AND AR.USER_ID NOT IN (select USER_ID from auth_user_roles where ACCESS_END_DATE > SYSDATE OR ACCESS_END_DATE IS NULL)', [':dept_group_id' => $dept_group_id ]);
This query does exactly what I want it to, but the problem is when I try to put it into a gridview it does not sort. According to Sort and search column when I'm querying with findbysql in yii2 it seems like I need to use query builder instead.
So I was trying to do that with the first part of my query (before the union), and it looks like so:
$query1 = (new \yii\db\Query())
->select(['user_id', 'last_name', 'first_name', 'emp_id'])
->from('AUTH_USERS');
$query2 = (new \yii\db\Query())
->select('USER_ID')
->from('AUTH_USER_ROLES')
->where('ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL');
$query = $query1->innerJoin('AUTH_USER_DEPTS', 'AUTH_USER_DEPTS.user_id = AUTH_USERS.user_id')->innerJoin('DEPARTMENTS', 'AUTH_USER_DEPTS.dept_id = DEPARTMENTS.dept_id');
$query->innerJoin('AUTH_USER_ROLES', 'AUTH_USER_ROLES.USER_ID = auth_users.USER_ID')->where('ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL');
However, my query comes out like this in yii and apparently oracle is not accepting the double quotes around the column names:
SELECT "user_id", "last_name", "first_name", "emp_id" FROM "AUTH_USERS"
INNER JOIN "AUTH_USER_DEPTS" ON AUTH_USER_DEPTS.user_id = AUTH_USERS.user_id
INNER JOIN "DEPARTMENTS" ON AUTH_USER_DEPTS.dept_id = DEPARTMENTS.dept_id
INNER JOIN "AUTH_USER_ROLES" ON AUTH_USER_ROLES.USER_ID = auth_users.USER_ID
WHERE ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL
I know the query might be incorrect here already but I cant even get the double quotes to go away. Tried defining the select statements multiple ways suggested by the yii docs already with no success:
select(['user_id', 'last_name', 'first_name', 'emp_id'])
select('user_id', 'last_name', 'first_name', 'emp_id')
select("user_id, last_name,first_name,emp_id")
I have also tried joining the queries like this from the docs: http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html
$query = $query1->innerJoin(['u' => $query2], 'u.user_id = user_id');
but it also complains that it doesnèt recognize u and the query instead comes out like so in yii:
SELECT COUNT(*) FROM "AUTH_USERS" INNER JOIN "AUTH_USER_DEPTS" ON AUTH_USER_DEPTS.user_id = AUTH_USERS.user_id INNER JOIN "DEPARTMENTS" ON AUTH_USER_DEPTS.dept_id = DEPARTMENTS.dept_id INNER JOIN (SELECT "USER_ID" FROM "AUTH_USER_ROLES" WHERE ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL) "u" ON u.user_id = auth_users.user_id
At this point im just looking for the easiest way to build this query (whether it be using querybuilder or some other way) so that I can pass the query to my gridview and sort it.
I would recommend you first create all the data models you need from the tables you need for the query, using Gii it should be easy and it even creates the relationships you will need.
After that, you can do something like the following:
$query = Users::find()
->joinWith('theRelation1Name')
->joinWith('theRelation2Name')
->joinWith('theRelation3Name')
...
This way you don't need to give tables aliases or add the conditions needed for the relations to work.

SQL Getting position in database WHERE from array

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.

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?

Zend Database Mutli table "Select" via Join

Using Zend DB. I am trying to figure out how to write this query using the DB Class.
select
org.orgid
org.role
user.userid
user.firstname
from orgTable org
join userTable user on org.userid = user.userid
where org.orgid = 'generated-id'
from the documents I understand or think I understand how to do it with one definition using an AS like condition, but even then Im still not sure. Eventually this will branch out into a multi table join, based on cross table conditions so not sure how to achieve this to begin with.
I think this is what are you looking for
$db = Zend_Db::factory( ...options... );
$select = $db->select()
->from(array('org' => 'orgTable'),
array(
'orgid' => 'org.orgid',
'role' =>'org.role',
'userid' =>'user.userid',
'firstname' =>'user.firstname'
))
->join(array('user' => 'userTable'),
'org.userid = user.userid',array())
->where('org.orgid = ?',$generated_id);
Here is a Zend_Db_Select that returns the result you are looking for.
$select = $db->select()
->from(array('org' => 'orgTable'), array('orgid', 'role'))
->join(array('user' => 'userTable'), 'org.userid = user.userid', array('userid', 'firstname'))
->where('org.orgid = ?', 'generated-id');
You can use the array notation for table names to get the aliased names in the query.
Hope that helps.
In zend framework 2 , the following code helps you what are you looking for
$generated_id = 1 ;
$select = new \Zend\Db\Sql\Select( array('org' =>'orgTable'));
$select->columns(array('orgid','role') )
->join( array('user' => 'userTable'),
'org.userid = user.userid',
array('userid','firstname')
)->where( array('org.orgid' => $generated_id ) );
if your adapter platform is mysql, then for printing sql
$mysqlPlatform = new \Zend\Db\Adapter\Platform\Mysql();
echo $select->getSqlString( $mysqlPlatform );
which print sql as
SELECT
`org`.`orgid` AS `orgid`,
`org`.`role` AS `role`,
`user`.`userid` AS `userid`,
`user`.`firstname` AS `firstname`
FROM
`orgTable` AS `org`
INNER JOIN `userTable` AS `user`
ON `org`.`userid` = `user`.`userid`
WHERE
`org`.`orgid` = '1'

Categories