DBIx::Class test agains mysql datetime function - mysql

I am using DBIx::Class and I would like to select rows based on what day of the year they were inserted on. Below is my query:
$rows = $c->model("DB::Test")->search(
{
"DAYOFYEAR(entry_time)"=>$day_of_year,
});
However this doesn't work because DBIx::Class treats DAYOFYEAR(entry_time) as a column. Is there anyway I could have it use that value litteraly? I know sometimes making it a scalar such as \'DAYOFYEAR(entry_time)' will work for some situations, but I've tried that and it doesn't work. Does anyone know of a way that I could do this? Thanks!

Using \ and 'DAYOFYEAR(entry_time)' is the right approach, and part of the FAQ.
[How do I] .. search with an SQL function on the left hand side?
To use an SQL function on the left hand side of a comparison you currently need to resort to literal SQL:
->search( \[ 'YEAR(date_of_birth) = ?', [ plain_value => 1979 ] ] );
Note: the plain_value string in the [ plain_value => 1979 ] part should be either the same as the name of the column (do this if the type of the return value of the function is the same as the type of the column) or in the case of a function it's currently treated as a dummy string (it is a good idea to use plain_value or something similar to convey intent). The value is currently only significant when handling special column types (BLOBs, arrays, etc.), but this may change in the future.

Related

Pass a 'null' value to a MySQL database in node.js

I'm trying to pass data from a Webscraper to a MySQL database. I have a lot of variables that need to be entered at a time into the database and below is a snippet of the code I'm using. (where the etc. is there are a bunch more variables.
con.query(INSERT INTO Paper_2 (referenceCodeSubject,referenceCode,subject, etc.) values ('"+referenceCodeSubject+"','"+referenceCode+"','"+subject+"', etc.))
The columns in the database have types INT, VARCHAR and CHAR.
My issue is that when I scrape not all of the variables will be assigned values and will remain as 'null' and I cannot pass this null as NULL to MySQL. It would also be quite complicated to sort the different cases for when to pass what due to the large amount of variables.
I'm hoping theres a simple way of doing this as the only solutions I've seen so far are omit the value in the query (which is hard because I would then need to decide which values to omit) or pass a string of "NULL" or just a value of 0. Is there any other way of doing this?
Better use the built in escaping feature to avoid sql injection attacks!
conn.query(
'INSERT INTO Paper_2 (referenceCodeSubject,referenceCode,subject) VALUES ?'
[
['refCodeSubject1', 'refCode1', 'subject1'],
['refCodeSubject2', 'refCode2', null]
],
(error, results, fields) => {
...
}
)
If you have the case, that the bind values can sometime be a valid string and sometimes undefined, use an or operator in sqlValues to handle both cases with shorthand code:
let nameValue;
let sql="insert into user (name) values (?)"
let sqlValues[] = [nameValue || null ]

Store results of expensive function calls in a MySQL table

Let's suppose I have a set of integers of a variable length. I apply a function on this set of integers and I obtain a result.
myFunction(setOfIntegers) => myResult
Let's suppose a call to myFunction is very expensive and I would like to somehow store the results of this function calls.
In my application I am already using MySQL and what I was thinking was to somehow create a table with the setOfIntegers as a PK and myResult as an additional field.
I was thinking that I could do this by transforming the setOfIntegers to a string before storing it in the DB.
Can this be done in any other way? Or would there be a better way to store results of such function calls in order to avoid calling them a 2nd time with the same set of integers?
I don't know about Java, but Perl has my $str = join(',', $array) and PHP has $str = implode(',', $array). Then the string $str could be used as the PRIMARY KEY (assuming it is not too long). And the result would go in the other column.
Your app code (in Java) would need to first do an implode and SELECT to see if the function has already been evaluated for the given array. If not, then perform the function and end by INSERTing a new row.
If this will be multi-threaded, you could use INSERT IGNORE to deal with dups. (There are other solutions, too.)
Another note: If your set-of-integers is ordered, then what I describe is 'complete'. If it is unordered, then sort it before imploding. This will provide a canonical representation.
If the function can be implemented in MySQL directly, I would suggest using Views.
https://www.mysqltutorial.org/mysql-views-tutorial.aspx/

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.

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.

Trick to use variable in match against mysql

Please first read my question,and then you will find out it is not a duplicate of other question.
I'm using sphinx search for 98% of search,but need to use match against for just one query.
As we know from mysql documentation that AGAINST only takes string.The search string must be a literal string, not a variable or a column name.
But I have found this link http://bugs.mysql.com/bug.php?id=66573 ,which says it is possible.But I'm not sure how to use that in my case.
Here is my code
$sqli="SELECT busi_title,category FROM `user`.`user_det`";
$queryi=mysqli_query($connecti,$sqli);
if(mysqli_num_rows($queryi)>0){
while($rowi=mysqli_fetch_assoc($queryi)){
$busi_title=$rowi['busi_title'];
$category=$rowi['category'];
}
}else{
echo "OH NO";
}
$sqlj="SELECT * FROM `user`.`user_det` WHERE MATCH(student) AGAINST('$busi_title','$category')";
$queryj=mysqli_query($connecti,$sqlj);
if(mysqli_num_rows($queryj)>0){
..............................
..............................
}else{
foreach ( $res["matches"] as $doc => $docinfo ) {
................................
...............................
}
}
MATCH() AGAINST() is giving error,as it supposed to be.How to use that trick of that link in this case.I don't know the use of #word:= of that link.
Thanks in advance.
That link doesn't show a trick to get around a limitation of MySQL. It's a bug report demonstrating an incorrect statement in the MySQL documentation. The statement in the documentation has now been corrected.
The reason you're getting an error is because you're sending two parameters to AGAINST and it only accepts one. You can use a MySQL variable in AGAINST which is what the bug report is about, but this has nothing to do with the PHP variable that you're using.
EDIT
Upon reading your response, I rather suspect that you have your syntax backwards.
SELECT * FROM `user`.`user_dets` WHERE MATCH(busi_title, category) AGAINST('student')
But note this from the documentation:
The MATCH() column list must match exactly the column list in some FULLTEXT index definition for the table, unless this MATCH() is IN BOOLEAN MODE. Boolean-mode searches can be done on nonindexed columns, although they are likely to be slow.
If you don't have a Fulltext index, you'll actually want this:
SELECT * FROM `user`.`user_dets` WHERE `busi_title` LIKE '%student%' OR `category` LIKE '%student%'
When they say "The search string must be a literal string, not a variable or a column name" does not mean you cannot use variable to create your Query String.
So it is OK to make your query very simple.
Your WHERE could be this:
WHERE `student` = $busi_title OR `student` = $category