What does it mean "?" in sql query? - sql

I just got a query cod :
SELECT o.id,o.sort_order,od.object FROM i_objects o, i_objects_description od
WHERE o.id=od.objects_id AND o.object_status = ? AND od.languages_id = ?
ORDER BY o.sort_order ASC
I want figure it out what does "?" mean in this query ?
If I run this query , it gives me this error :
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 '?
Im using PEAR and this is my function :
function getArrayObjects( $language_id )
{
$q = 'SELECT o.id,o.sort_order,od.object FROM ' . TABLE_OBJECTS . ' o, ' . TABLE_OBJECTS_DESCRIPTION . ' od ';
$q.= 'WHERE o.id=od.objects_id AND o.object_status = ? AND od.languages_id = ? ';
$q.= 'ORDER BY o.sort_order ASC';
$sth = $this->_db->prepare( $q );
$res = $sth->execute( array( 'active', $language_id ) );
//var_dump($res);echo "<br>";echo "<br>";echo "<br>";
$objects = array();
while( $row = $res->fetchRow())
{
$objects[$row['id']] = $row;
}
return $objects;
}

It's a placeholder for parameter. In your query you have this:
AND o.object_status = ? AND od.languages_id = ?
And then you execute it like this:
$res = $sth->execute( array( 'active', $language_id ) );
So, when query is actually executed by database server, object_status is 'active' and language_id is $language_id.
This is done this way to guard from SQL injection. Another reason is efficiency. When you use prepared statements, database doesn't need to parse/compile query each time. It uses the template and just substitutes values in it. (more on this: Prepared statement)

The ? are placeholder the values of which are filled in in the $sth->execute( array( 'active', $language_id ) ) statement.
One of the main purposes for this construct is to prevent sql injection attacks.

Its a Used to set the value dynamically ,in other words place holder

These are "parametrized queries". While evaluating "?" are replaced with given values (it's called binding). They protect from sql injection and makes possible to optimize queries.

Related

Why does a UNION ALL query treat the outer ORDER column as unknown?

I'm using unionAll() and return the data perfectly, but I need ordernate the data and always return error because the column not exists.
$events = $this->Events
->find('available')
->where([
'Events.group_of_event_id IS NULL'
])
->select('Events.id')
->select('Events.name')
->select('Events.slug')
->select('Events.date_event_start')
->select([
'is_group' => 0
]);
$groups = $this->GroupOfEvents
->find('available')
->select('GroupOfEvents.id')
->select('GroupOfEvents.name')
->select('GroupOfEvents.slug')
->select('GroupOfEvents.date_event_start')
->select([
'is_group' => 1
]);
$limit = 10;
$page = 1;
if($this->request->query('limit'))
$limit = $this->request->query('limit');
if($this->request->query('page'))
$page = $this->request->query('page');
$offset = ($page - 1) * $limit;
$connection = ConnectionManager::get('default');
$union = $events->unionAll($groups)->epilog(
$connection
->newQuery()
->order(['date_event_start' => 'ASC'])
->limit($limit)
->offset($offset)
);
Return this error:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'date_event_start' in 'order clause'
As the error states, there is no date_event_start column.
Unlinke normale SQL queries, where a non-table prefixed column would fall back to referring to one of the involved tables, similar doesn't happen for union results, with union results you have to explicity refer to the columns as they have been selected.
So you have to make sure that either the columns are selected without a table prefix, or to select and use proper aliases in the ORDER clause. In order to avoid ambiguity, I'd strongly suggest going for the latter, something like
->select(['date_event_start_alias' => 'Events.date_event_start'])
// ...
->select(['date_event_start_alias' => 'GroupOfEvents.date_event_start'])
// ...
->order(['date_event_start_alias' => 'ASC'])
It should be noted that at least with MySQL and Postgres (I'm not sure about other DBMS like SQLite or SQL Server), you actually have to set the alias only for the first SELECT. Setting it for all selects won't do any harm, so I'm including it in the example, but it's not actually necessary.
See also
Cookbook > Database Access & ORM > Query Builder > Selecting Data

Intersect two SQL statement in Yii?

I want to apply an intersect operator on two SQL queries, but I couldn't find any Yii method for it in CDbCommand. Is there any?
Unfortunately there is no INTERSECT operator in Yiis CDbCommand. But you can use "pure" SQL to make queries.
Examples:
$sql = "first select INTERSECT second select";
$result = Yii::app()->db->createCommand($sql)->queryAll();
You could also use CDbCommands for making single queries, just use buildQuery() on them. It will looks like:
$firstSql = 'define sql here';
$firstSql->where('your condition');
$secondSql = 'define sql here';
$secondql->where('your condition');
$sql = buildQuery($firstSql) . ' INTERSECT ' . buildQuery($secondSql);
$result = Yii::app()->db->createCommand($sql)->queryAll();
Hope it will help you!

Using more than one queries on perl DBI

I'm sure there is a better way to do this on the same line, but I'm unable to figure out how, since I'm a beginner in Perl. Basically what I need to do is select, delete and count the results.
$sth = $dbh->prepare("SELECT env,server, mwp.is_reference where env='$ARGV[1]';");
$sth->execute();
$sth2 = $dbh->prepare("delete from mwp.is_info_package where env='$ARGV[1]'");
$sth2->execute();
$sth3 = $dbh->prepare("SELECT count(1) from mwp.is_reference where env='$ARGV[1]'");
$sth3->execute()
The objective is how do i use the 3 queries at the same line, instead having 3 executes.
Well you could start out using placeholders ( '?' ).
my #qlist
= ( 'SELECT env,server FROM mwp.is_reference where env=?'
, 'DELETE mwp.is_info_package WHERE env=?'
, 'SELECT count(1) FROM mwp.is_reference where env=?'
);
And then you can iterate through them like this:
my $env = $ARGV[1];
foreach my $query ( #qlist ) {
$dbh->prepare( $query )->execute( $env );
Carp::croak( $dbh->errstr ) if $dbh->err;
}
But of course, you really want to select the two outputs, don't you?
use Carp qw<croak>;
my $select_query = 'SELECT env,server FROM mwp.is_reference where env=?';
my $delete_query = 'DELETE mwp.is_info_package WHERE env=?';
my $count_query = 'SELECT count(1) FROM mwp.is_reference where env=?';
my %empty_atts;
my $rows
= $dbh->selectall_arrayref( $select_query, \%empty_atts, $env )
;
croak( $dbh->errstr ) if $dbh->err;
$dbh->prepare( $delete_query )->execute( $env );
croak( $dbh->errstr ) if $dbh->err;
my ( $count )
= $dbh->selectrow_array( $count_query, \%empty_atts, $env )
;
croak( $dbh->errstr ) if $dbh->err;
I solved the problem using the following query statement:
$sth = $dbh->prepare("select env,iserver, ( select count(1) from is_reference where env='$ARGV[1]' ) as total from is_reference where env='$ARGV[1]'");
not the most elegant way, but solved my problem with the less lines. Regarding the delete query, i moved to another condition to check if the table have data or not.
THanks all.
You could use a stored procedure that performs those functions and returns the results of the select as well as a count, then you only need to do:
my $sth = $dbh->prepare("EXEC procedure_name ?");
$sth->execute( $ARGV[1] );
As an aside, the way you're using prepare and execute is undesirable. You use prepare to avoid having to have Perl variables directly in the query; your Perl variables should be passed to execute() as values, not part of the string given to prepare(). There are a number of good reasons to do this, including protection against SQL Injection attacks.
I also noticed oddness in your last SQL query. I think you probably want
SELECT count(env) FROM mwp.is_reference where env=?
Otherwise it will always return "1" as the count... Likewise, unless there are database triggers doing something interesting, you could combine the first and last query into one this way (I'll leave count(1) for this in case that's really what you want):
my $sth = $dbh->prepare('SELECT env,server FROM mwp.is_reference where env=?');
$sth = $sth->execute( $ARGV[1] );
my $result_set = $sth->fetchall_arrayref();
my $count = scalar #{ $result_set };
The $result_set will be a reference to an ARRAY of ARRAYRefs containing the results; $count will contain the number of rows in that result set.

How can I generate the SQL query using SQL::Abstract?

How do I generate the WHERE clause for this query using SQL::Abstract:
SELECT COUNT(*) FROM table WHERE id =
111 AND NOT FIND_IN_SET(type,
'1,2,3,4') AND status = 'pending';
What's the proper way to include conditions like WHERE FIND_IN_SET(type, '1,2,3,4')?
See the not_bool unary operator option:
use SQL::Abstract;
my $sql = SQL::Abstract->new;
my $where = {
id => 111,
status => 'pending',
-not_bool => "FIND_IN_SET(type, '1,2,3,4')",
};
my ($query, #bind) = $sql->select(
'table',
'count(*)',
$where,
);
This is how $query looks:
SELECT count(*) FROM table WHERE ( ( (NOT FIND_IN_SET(type, '1,2,3,4'))
AND id = ? AND status = ? ) )
This code generates the WHERE clause:
my $sql = SQL::Abstract->new;
my %where = (
id => 111,
-nest => \"NOT FIND_IN_SET(type, '1,2,3,4')",
status => 'pending',
);
my ($stmt, #bind) = $sql->where(\%where, \#order);
FIND_IN_SET isn't standard SQL, so SQL::Abstract doesn't have support for it. You can however put any literal SQL into an SQL::Abstract query. I expect your solution lies down that route.
Take a look at: DALMP
Database Abstraction Layer for MySQL using PHP
0% fat and extremely easy to use. Only connect to database when needed.
http://code.google.com/p/dalmp/

Is there SQL parameter binding for arrays?

Is there a standard way to bind arrays (of scalars) in a SQL query? I want to bind into an IN clause, like so:
SELECT * FROM junk WHERE junk.id IN (?);
I happen to be using Perl::DBI which coerces parameters to scalars, so I end up with useless queries like:
SELECT * FROM junk WHERE junk.id IN ('ARRAY(0xdeadbeef)');
Clarification: I put the query in its own .sql file, so the string is already formed. Where the answers mention creating the query string dynamically I'd probably do a search and replace instead.
Edit: This question is kind of a duplicate of Parameterizing a SQL IN clause?. I originally thought that it should be closed as such, but it seems like it's accumulating some good Perl-specific info.
If you don't like the map there, you can use the 'x' operator:
my $params = join ', ' => ('?') x #foo;
my $sql = "SELECT * FROM table WHERE id IN ($params)";
my $sth = $dbh->prepare( $sql );
$sth->execute( #foo );
The parentheses are needed around the '?' because that forces 'x' to be in list context.
Read "perldoc perlop" and search for 'Binary "x"' for more information (it's in the "Multiplicative Operators" section).
You specify "this is the SQL for a query with one parameter" -- that won't work when you want many parameters. It's a pain to deal with, of course. Two other variations to what was suggested already:
1) Use DBI->quote instead of place holders.
my $sql = "select foo from bar where baz in ("
. join(",", map { $dbh->quote($_) } #bazs)
. ")";
my $data = $dbh->selectall_arrayref($sql);
2) Use an ORM to do this sort of low level stuff for you. DBIx::Class or Rose::DB::Object, for example.
I do something like:
my $dbh = DBI->connect( ... );
my #vals= ( 1,2,3,4,5 );
my $sql = 'SELECT * FROM table WHERE id IN (' . join( ',', map { '?' } #vals ) . ')';
my $sth = $dbh->prepare( $sql );
$sth->execute( #vals );
And yet another way to build SQL is to use something like SQL::Abstract....
use SQL::Abstract;
my $sql = SQL::Abstract->new;
my $values = [ 1..3 ];
my $query = $sql->select( 'table', '*', { id => { -in => $values } } );
say $query; # => SELECT * FROM table WHERE ( id IN ( ?, ?, ? ) )
With plain DBI you'd have to build the SQL yourself, as suggested above. DBIx::Simple (a wrapper for DBI) does this for you automatically using the '??' notation:
$db->query("select * from foo where bar in (??)", #values);
In python, I've always ended up doing something like:
query = 'select * from junk where junk.id in ('
for id in junkids:
query = query + '?,'
query = query + ')'
cursor.execute(query, junkids)
...which essentially builds a query with one '?' for each element of the list.
(and if there's other parameters in there too, you need to make sure you line things up correctly when you execute the query)
[edit to make the code easier to understand for non-python people. There is a bug, where the query will have an extra comma after the last ?, which I will leave in because fixing it would just cloud the general idea]
I use DBIx::DWIW. It contains a function called InList(). This will create the part of the SQL that is needed for the list. However this only works if you have all your SQL in the program instead of outside in a separate file.
Use
SELECT * FROM junk WHERE junk.id = ANY (?);
instead