Use "Alias" in "Select" With Medoo - select

I'm using the Medoo framework.
I need this query:
Select a.name, b.name from section as a left join section as b on(a.idsection=b.section_idfather)
In the Medoo format:
$Data = $database->select("section",
[
"[>]section" => ["idsection" => "section_idfather"]
],
[
"section.name",
"section.name",
]
]);
How can I do this query in the right Medoo format??

So, I change a litty the original file to get assign an ALIAS to the Select Columns:
1) Add in the LINE: 127
protected function column_quote_as($string)
{
return str_replace('.', '.', $string);
}
2) Add in the LINE: 405 (original line)
foreach($columns AS $Columns){
$columnsTemp =explode('[>]',$Columns);
$columnsVal = ($columnsTemp[1]!='') ? '`' . $columnsTemp[0] . '` AS \'' . $columnsTemp[1] . '\'':'`' .$columnsTemp[0] . '`';
$ColumnsEnd[] = $columnsVal;
}
3) Change the LINE: 408 (original line)
is_array($ColumnsEnd) ? $this->column_quote_as( implode(', ', $ColumnsEnd) ) :
And now, the new format to take the query is:
$Data = $database->select("section",
[
"[>]section" => ["idsection" => "section_idfather"]
],
[
"section.name[>]SecName",
"section.name[>]SecNameFather",
]
]);

You can use parentheses to add an alias for a column name.
$data = $database->select("account", [
"user_id",
"nickname (my_nickname)"
]);
For joins:
$data = $database->select("post (content)", [
"[>]account (user)" => "user_id",
], [
"content.user_id (author_id)",
"user.user_id"
]);

Related

Why `select` does not replace existing columns?

DOC for select attribute:
select indicates which columns should be selected from the storage
This works as expected:
$rs->search( undef, { select => [ 'me.id', 'me.user_id' ] } )
->search( undef, { select => [ 'me.role_id' ] } )
$rs->as_query; # SELECT "me"."role_id" FROM "users_roles" "me"
But this does not:
$rs->search( undef, { prefetch => [ 'User' ] } )
->search( undef, { select => [ 'User.name' ] } )
$rs->as_query; # SELECT "User"."name", "User"."id", "User"."email", "User"."name" FROM "users_roles" "me" JOIN "users" "User" ON "User"."id" = "me"."user_id"
The prefetch implies +columns ( which is: +select and +as ).
I alter select in second search by requesting only one column: name
What did I miss?
Why I still get columns name, id, email, name instead of only one name?
If I rewrite prefetch by join. This works fine:
$rs->search( undef, {
,join => [ 'User' ]
,collaplse => 1
,'+columns' => [map
{ +{ "cds.$_" => "cds.$_" } }
$c->db->source('Right')->related_source('User')->columns
]
})->search( undef, { select => [ 'User.name' ] } )
$rs->as_query; # SELECT "User"."name" FROM "users_roles" "me" JOIN "users" "User" ON "User"."id" = "me"."user_id"
So it seems there is a bug with prefetch. Because join+collapse++columns is not same as prefetch:
DOC
This attribute is a shorthand for specifying a "join" spec, adding all columns from the joined related sources as "+columns" and setting "collapse" to a true value.
Also docs states:
For example, the following two queries are equivalent
As you can see join and prefetch are not equivalent

How to search data in two phalcon tables

Someone could explain me How to search data in two phalcon tables:
I have this query:
$Q = $this->request->getPost("data");
$phql = 'SELECT b.idbank,b.name,m.description,m.date
FROM bank b
inner join movement m on b.idbank=m.idbank
WHERE b.estado = 1 and b.name like "%'.$Q.'%" or m.description like "%'.$Q.'%"
Order by b.idbank desc
';
$bank = $this->modelsManager->executeQuery($phql);
There would be some way to do it this way:
$Q = $this->request->getPost("data");
$bank = Bank::find([
"name like '%:dato:%'",
"bind" => [
"dato" => $Q
]
]);
$mov = $bank->getmovement([
"description like '%:dato:%'",
"bind" => [
"dato" => $Q
]
]);
$bank = $mov->bank;
I actually do not know how to do it.
What I did is not working for me.
You need to move the percents from the condition placeholder to your bind parameters. Your first query reworked:
$bank = Bank::find([
"name like :dato:",
"bind" => [
"dato" => '%'. $Q .'%'
]
]);
More examples in the Documentation.

DBIx::Class: How can I sort on multiple substrings of a column?

I have a SQLite-database with table with a document number following this schema:
16-145-45
16-127-30
16-141-42
16-122-14
15-090-04
15-089-15
15-089-05
I'd like to sort the ResultSet on the first and last part of the number, like this. First, all documents starting with the highest two-digit prefix (16) sorted by the last 2 digits and then the same with the next block, and so on.
16-145-45
16-141-42
16-127-30
16-122-14
15-089-15
15-089-05
15-090-04
Is there a way to do this in DBIx::Class with some sort of custom order_by clause, or what would be the approach?
I have tried the following, which does not work, because the middle part of the number is also considered for sorting:
my #rs = $self->search(undef,
{
order_by => { -desc => 'me.number' }
}
);
If you want the database to sort the results, you have to use literal SQL.
Here's an example for Postgres (I added a space after the backslash to fix the syntax highlighting):
my #rs = $self->search(undef,
{
order_by => \ "split_part(number, '-', 1) || split_part(number, '-', 3) DESC",
}
);
Or, by creating an output column with the +select result set attribute:
my #rs = $self->search(undef,
{
'+select' => [
{ sort_key => \ "split_part(number, '-', 1) || split_part(number, '-', 3)" },
],
'+as' => [ qw(sort_key) ], # Make sort key accessible from DBIC.
order_by => { -desc => 'sort_key' },
}
);
Another approach is to retreive the whole unsorted result set, and sort it on the client side. DBIC doesn't have any specific features to help you with that, so simply use Perl's sort function.
Since the answer from #nwellnhof works like a charm, I just wanted to provide the corresponding syntax for SQLite, which does not know the split_part() function.
# SQL for filtering the doc number in SQLite
my #rs = $self->search(undef,
{
order_by => \ "SUBSTR(me.number, 1, 2) || SUBSTR(me.number, -2, 2) DESC"
}
);
You need to extract additional columns from the result set which are equal to the value of the function that you want to sort by. Then you can just put those columns in an order_by clause as normal
This assumes that your document number field is called docnum. It fetches all the columns from Table plus the two substrings of docnum called docnum1 and docnum3
my $rs = $schema->resultset('Table')->search(undef,
{
'+select' => [
{ substr => [ 'docnum', 1, 2 ], -as => 'docnum1' },
{ substr => [ 'docnum', -2 ], -as => 'docnum3' },
],
order_by => [ { -desc => 'docnum1' }, { -desc => 'docnum3' } ],
}
);

Alias the sum of two columns in a DBIx::Class resultset

SELECT me.id, me.date_created, me.date_updated, me.yes,
me.name, me.description, me.currency, me.locked, me.skip,
me.uri_part, me.user_id,
yes + currency as weight
FROM ideas me having ((weight < 5)) order by weight;
How can I generate that query in DBIx::Class without using literal SQL like this:
my $query = $rs->search({},
{
'+select' => \[
'yes + currency as weight',
],
rows => 1,
order_by => { -desc => [qw/weight name/] },
having => {
weight => { '<' => $self->yes + $self->currency },
},
});
use Data::Dumper;
warn Dumper($query->as_query);
I tried using -as, however, it seems to only be useful for working with columns generated from functions, as this:
'+select' => {
'yes + currency', '-as' => 'weight'
}
generates an error
"Odd number of elements in anonymous hash at
/data/TGC/lib/TGC/DB/Result/Idea.pm line 105, line 1000.
DBIx::Class::SQLMaker::_recurse_fields(): Malformed select argument -
too many keys in hash: SCALAR(0xbf14c40),weight"
Probably the most idiomatic thing I can think of in SQL Abstract expression, without straining too hard:
#!/usr/bin/env perl
use Modern::Perl;
use MySchema;
use Data::Dumper;
my $schema = MySchema->connect('dbi:SQLite:example.db');
my $rs = $schema->resultset('Sample')->search(
{
weight => { '<' => 5 },
},
{
'+select' => [
{ '' => \'`me`.`yes` + `me`.`currency`', -as => 'weight' }
]
}
);
say Dumper( $rs->as_query() );
Which is a contrived wrapping of the column names, but it does the job, sort of. Just don't know of any way to abstract the + here. But stil:
'(SELECT me.name, me.yes, me.currency, ( me.yes + me.currency ) AS weight FROM sample me WHERE ( weight < ? ))',
Unless you are just going for idiomatic perl, in which case:
{ '' => \(join " + ", qw/`me`.`yes` `me`.`currency`/), -as => 'weight' }
But either way seems a little contrived considering both forms are longer than the literal string.
Also note that weight is referenced in WHERE and not HAVING which is because that will blow up on various SQL engines.
The '+as' should be at the same level as '+select'
$idea = $rs->search({-and => [
name => { '<' => $self->name },
]},
{
'+select' => [
'yes + currency'
],
'+as' => [qw/weight/],
rows => 1,
order_by => ['weight', 'name'],
having => {
weight => { '<' => $self->yes + $self->currency },
},
})->single;

How to make FormValidator::Simple to use the same rule for multiple keys?

Now it just looks very verbose:
key1 => THE_SAME_RULE,
key2 => THE_SAME_RULE,
..
keyn => THE_SAME_RULE,
Is there a way to express this in more concise manner?
The values are just data so you could have an extra variable that holds the rule and then refer to that variable when building your rule set. For example:
my $email = ['NOT_BLANK', 'EMAIL_LOOSE'];
my $result = FormValidator::Simple->check( $query => [
mail1 => $email,
mail2 => $email,
] );
In theory, you could build up a whole library of rules and then use that library everywhere:
my $result = FormValidator::Simple->check( $query => [
mail => $AskersRules::EMAIL,
phone => $AskersRules::PHONE,
# etc.
] );
Then you wouldn't have to repeat yourself and you'd have a central library for both re-use and testing purposes.
I think you can also do this:
{ ks => [ 'key1', 'key2' ] } => THE_SAME_RULE
if that's what you're after. From the fine manual:
my $result = FormValidator::Simple->check( $q => [
{ mails => ['mail1', 'mail2'] } => [ 'DUPLICATION' ],
] )
So you want a loop, and you want it inside an expression. That begs for map.
( map { $_ => THE_SAME_RULE } qw( key1 key2 .. keyn ) )