Zend Framework - mysql query - mysql

$xyz = mysql_fetch_array(mysql_query('select sum(value) points where userId = $userIdDB'))['suma'];
How that query will looks in zend framework? I need to select sum of records from DB as int.
And another question: can i make mysql queries. I dont have in real any knowledge from zend, so I please for full explanation.
What about mysql connections in zend?

In ZEND
$select = $db->select()
->from('points',array(new Zend_Db_Expr('sum(value)')))
->where('userId = ?', $userIdDB);
When Adding Expression Columns
Columns in SQL queries are sometimes expressions, not simply column
names from a table. Expressions should not have correlation names or
quoting applied. If your column string contains parentheses,
Zend_Db_Select recognizes it as an expression.
You also can create an object of type Zend_Db_Expr explicitly, to
prevent a string from being treated as a column name. Zend_Db_Expr is
a minimal class that contains a single string. Zend_Db_Select
recognizes objects of type Zend_Db_Expr and converts them back to
string, but does not apply any alterations, such as quoting or
correlation names.
EXAMPLE IN ZEND
// Build this query using Zend_Db_Expr explicitly:
// SELECT p."product_id", p.cost * 1.08 AS cost_plus_tax
// FROM "products" AS p
$select = $db->select()
->from(array('p' => 'products'),
array('product_id',
'cost_plus_tax' =>
new Zend_Db_Expr('p.cost * 1.08'))
);

Related

Searching for multiple values in 1 query

If I have a database having 2 fields, Roll no and name and I have a list (of n values) of roll numbers for which I have to search the corresponding names.
Can this be done using just one query in SQL or HQL?
SELECT name FROM [table] WHERE id IN ([list of ids])
where [list of ids] is for example 2,3,5,7.
Use the IN operator and separate your Roll no's by a comma.
SELECT name
FROM yourtable
WHERE [Roll no] IN (1, 2, 3, 4, etc)
You can use the IN statement as shown above.
There are a couple of minor issues with this. It can perform poorly if the number of values in the clause gets too large.
The second issue is that in many development environments you land up needing to dynamically create the query with a variable number of items (or a variable number of placeholders if using parameterised queries). While not difficult if does make your code look messy and mean you haven't got a nice neat piece of SQL that you can copy out and use to test.
But examples (using php).
Here the IN is just dynamically created with the SQL. Assuming the roll numbers can only be integers it is applying intval() to each member of the array to avoid any non integer values being used in the SQL.
<?php
$list_of_roll_no = array(1,2,3,4,5,6,7,8,9);
$sql = "SELECT FROM some_table WHERE `Roll no` IN (".implode(", ", array_map ('intval', $list_of_roll_no)).")";
?>
Using mysqli bound parameters is a bit messy. This is because the bind parameter statement expects a variable number of parameters. The 2nd parameter onwards are the values to be bound, and it expects them to be passed by reference. So the foreach here is used to generate an array of references:-
<?php
$list_of_roll_no = array(1,2,3,4,5,6,7,8,9);
if ($stmt = $mysqli->prepare("SELECT FROM some_table WHERE `Roll no` IN (".implode(",", array_fill(0, count($list_of_roll_no), '?')).")"))
{
$bind_arguments = [];
$bind_arguments[] = str_repeat("i", count($list_of_roll_no));
foreach ($list_of_roll_no as $list_of_roll_no_key => $list_of_roll_no_value)
{
$bind_arguments[] = & $list_of_roll_no[$list_of_roll_no_key]; # bind to array ref, not to the temporary $recordvalue
}
call_user_func_array(array($statement, 'bind_param'), $bind_arguments);
$statement->execute();
}
?>
Another solution is to push all the values into another table. Can be a temp table. Then you use an INNER JOIN between your table and your temp table to find the matching values. Depending on what you already have in place then this is quite easy to do (eg, I have a php class to insert multiple records easily - I just keep passing them across and the class batches them up and inserts them occasionally to avoid repeatedly hitting the database).

how to sort varchar column containing numeric values with linq lambdas to Entity

I am using linq lambdas to query the MySql (Note MySql not Sql) with Entity Framwork in MVC. Now i have one table product one of column this table is price with datatype "VARCHAR" (Accept i can't change type to INT as it can hold values like "N/A",etc).
I want to sort price column numerically with linq Lambdas.I have tried bellow.I am using Model values to filter query.
var query = ent.Product.Where(b => b.cp == Model.CodePostal);
if (Model.order_by_flg == 2)
{
query = query.OrderByDescending(a => a.price.PadLeft(10, '0'));
}
But it will not work and give me bellow error.
LINQ to Entities does not recognize the method 'System.String
PadLeft(Int32, Char)' method, and this method cannot be translated
into a store expression.
As it cant convert to Sql statement by Entity Framwork.
I also tried bellow.
var query = ent.Product.Where(b => b.cp == Model.CodePostal);
if (Model.order_by_flg == 2)
{
query = query.OrderByDescending(a => a.price.Length).ThenBy(a => a.price);
}
But i can't do this because it works for List but i cant first make list and then do this as i am using linq Skip() and Take() so first i have to sort it.
So how can i sort price column of type "VARCHAR" in Linq lambda?
EDIT
In table it is :
59,59,400,185,34
Wnen i use OrderBy.ThenBy it gives
34,59,59,106,185,400
It looks right as sorting ascending But when i use OrderByDescending.ThenBy it gives
106,185,400,34,59,59
So i can't use this.
NOTE: Please give reasons before Downvote so i can improve my question...
You can simulate fixed PadLeft in LINQ to Entities with the canonical function DbFunctions.Right like this
instead of this
a.price.PadLeft(10, '0')
use this
DbFunctions.Right("000000000" + a.price, 10)
I haven't tested it with MySql provider, but canonical functions defined in the DbFunctions are supposed to be supported by any provider.
It looks right as sorting ascending But when i use OrderByDescending.ThenBy it gives
106,185,400,34,59,59
That's because you're ordering by length descending, then value ascending.
What you need is simply to sort both by descending;
query = query.OrderByDescending(a => a.price.Length)
.ThenByDescending(a => a.price);
This should be faster than prepending numbers to sort, since you don't need to do multiple calculations per row but can instead sort by existing data.

Pass array in raw MySQL query in Ruby on Rails

So, I have a problem. I have a query which returns ids from one table (say table1) and I have to pass those ids to another query which uses table2. (Writing inner selects or joins is not an option due to some certain reasons).
Query:
client = Mysql2::Client.new(:host => "localhost", :username => "", :password => "", :database =>"test")
query1 = %Q{select id from table1 where code='ABC123'}
ids = client.query(query1)
query2 = %Q{select * from table2 where `table2`.`table1_id` IN (#{ids}) and status="rejected"}
table2_data = client.query(query2)
ids is Mysql2::Result type
Also, when I do ids.to_a, the resulting array has data something like this: [{"id"=>1}, {"id"=>2}]
I need some feasible way to pass ids to the second query. I tried ids.to_a, but it gives error due to the braces [ ]. I have also tried concatenating, say the MySQL result is:
array = ids.to_a # [1,2,3]
id_new = "("+#{array.join(',')}+")"
id_new becomes "(1,2,3)" which is a string and hence IN doesn't work.
Can anyone please suggest something how to pass ids array in the raw MySQL query?
I have banged my head finding the answer, but couldn't find an appropriate one.
Edit: I can use Active Record only for query1 and if that is the case and ids is an Active Record object, can anyone suggest how to pass it to query2 in the IN clause which is supposed to be a raw SQL query?
Edit2: I can't use Active Record (for query2) or join because it's making the query heavy and taking long time (>10s) to fetch the result (indices are present). So, I am using raw query to optimise it.
When I ran similar queries to try to mimic your problem I saw that I'm getting an array of array for ids, like [["1"], ["2"], ["3"]].
If this is also what you're getting then you should call ids.flatten before calling join:
query2 = %Q{select * from table2 where `table2`.`table1_id` IN (#{ids.flatten.join(',')}) and status="rejected"}
array.flatten removes extra braces, so:
[[1], [2], [3]].flatten
# => [1,2,3]
[[1], [2], [3]].flatten.join(',')
# => "1,2,3"
EDIT
Since you reported you are receiving a Mysql2::Result object, do this:
ids.to_a.map(&:values).flatten.join(',')
The to_a first converts the Mysql2::Result to an array of hashes that looks like this:
[{"id"=>"1"}, {"id"=>"2"}]
Then using map(&:values) we convert it to an array that looks like this:
[["1"], ["2"]]
This array is similar to the above (before the edit), so running flatten.join(',') converts it to the string you are looking for.
Note that instead of doing map(&:values).flatten you could use the common shortcut flat_map(&:values) which results in the same thing.
Are you sure it doesn't work because it is a string. I think it doesn't work because of duplicate brackets. Please try this:
array = ids.flat_map(&:values).join(',')
query2 = %Q{select * from table2 where `table2`.`table1_id` IN (#{array}) and status="rejected"}
I suggest to use a ORM (object-relational mapping) like the ActiveRecord or Sequel gems - especially because building database queries manually by string concatination is error prone and leads to vulnerabilities like sql injections.
If the main reason you posted was to learn how to extract data from an array of hashes, then you can ignore this answer.
However, if you wanted the best way to get the data from the database, I'd suggest you use ActiveRecord to do the donkey work for you:
class Table1 < ActiveRecord::Base
self.table_name = :table1
has_many :table2s
end
class Table2 < ActiveRecord::Base
self.table_name = :table2
belongs_to :table1
end
table2_data = Table2.joins(:table1).where(table1: {code: 'ABC123'}, status: 'rejected')
A key point is that a SQL join, will effectively do the processing of the IDs for you. You could code up the SQL join yourself, but ActiveRecord will do that for you, and allow you to add the additional queries, such that you can gather the data you want in one query.
You can join array with comma, like following code.
ids = ids.to_a.map{|h| h['id']}
query2 = %Q{select * from table2 where `table2`.`table1_id` IN (#{ids.join(',')}) and status="rejected"}
table2_data = client.query(query2)
It will work fine.

What does it mean the colon in queries yii2 framework?

I'm totally new in yii2 and I want to know what does it mean the colon in the query?
I have made a research about binding parameters, but in the yii2 documentation says:
// returns all inactive customers
$sql = 'SELECT * FROM customer WHERE status=:status';
which side is from the data base? the left side or the right side?
which is a simple text and which one is a column from the DB? Im so confused.
what would be another way to make the query without the colon? is it valid?
why it has 'anyo = **:**valor' in the next example? and some others dont?
$dbLibro = Libro::find()->where('tipo = "Nacimiento"')->andWhere('cerrado = 0')->andWhere('anyo = :valor',[':valor'=>date("Y")])->one();
I hope its clear cause the documentation is a bit confusing for me.
The colons are not directly related with Yii2, it's related with PHP PDO extension that used by Yii2.
Each colon is placeholder used later for binding value. Check for example this question.
If we write this query in ActiveQuery:
SELECT * FROM customer WHERE status = :status
we can get something like this:
$query = Customer::find()->where('status = :status', [':status' => Customer::STATUS_ACTIVE]);
Assuming STATUS_ACTIVE constant equals to 1, after execution it transforms to this:
SELECT * FROM "customer" WHERE status = 1
So the left side (before equals) represents column name, right part - value which will be safely binded after.
But you don't have to write params by yourself, Yii2 QueryBuilder generates it automatically for you.
There are other ways to write query without colons and they are used more often. This query can be written like this:
$query = Customer::find(['status' => Customer::STATUS_ACTIVE]);
$models = $query->all();
Or like this using shortcut:
$models = Customer::findAll(['status' => Customer::STATUS_ACTIVE]);
Or it can be even put inside of a scope:
$models = Customer::find()->active();
In this case Yii generates parameters automatically and it will be equivalent to this:
SELECT * FROM "customer" WHERE "status"=:qp1
Value 1 will be binded to :qp1 parameter, note that in this case column names are also double quoted.
If you try to use more conditions, params will be :qp2, :qp3 and so on (default PARAM_PREFIX is :qp).
As for your second query, it can be rewritten like this:
$model = Libro::find()
->where([
'tipo' => 'Nacimiento',
'cerrado' => 0,
'anyo' => date('Y'),
])->one();
Such queries look way better and readable in this state.
Yii2 allows generate even more complex conditions in queries, check this section of the docs for more details.
P.S. It's better to use english for naming in your code. Think about other international developers supporting your code. date('Y') can be calculated using database functions depending on used RDBMS.

JDBC prepareStatement doesn't work

I'm trying to use the prepareStatement function. The code is below. After it executes, it returns me a bunch of vlicense strings instead of the values.
When the code finishing the statement.setString(), the statement becomes:
select 'vlicense' from Vehicle
However, it needs to be:
select vlicense from Vehicle
without the quotation marks. Can anyone tell me what's the problem?
statement = oConnection.prepareStatement("select ? from Vehicle");
String tempString = "vlicense";
statement.setString(1, tempString);
resultSet = statement.executeQuery();
You can't use parameter markers for column names, table names, data type names, or basically anything that isn't data.
When you add a bind variable to a statement like this it is escaped, so that actual SQL string in your example would go to the database as "SELECT 'vlicense' FROM Vehicle', selecting a literal string instead of the column name you want.
You need to concatenate that variable column name into your SQL statement before you prepare it:
statement = oConnection.prepareStatement("SELECT " + vlicense + " FROM Vehicle");
Bind variables are really for query parameters as opposed to dynamic queries.
The ? can't be used to specify the fields, just to do some filters in your query like:
statement = conn.prepareStatement("select field from Vehicle where name=?");
In your case your query is built as:
select 'vlicense' from Vehicle
which means: GET ME A STRING 'vlicense' FOR EACH RECORD OF 'Vehicle'. And you'll get n repeated strings depending on the number of records in your table
It has nothing to do with jdbc, prepared-statements or mysql.
It's just a wrong sql statement.
If you type:
Select 'justanexample' from Vehicle
and the table contains 4 lines, you will get 4 times
'justanexample'
'justanexample'
'justanexample'
'justanexample'
as result.
You did not specify your the table structure, but I guess the
statement should somehow look like this:
select * from Vehicle where license = ?