SQL query to cakePHP format (invalid json result) - sql

Hello I have a PostgreSQL query that I would like to write using cakePHP format
SELECT
id,
title,
author,
postdate,
postcontent,
userID
FROM posts
WHERE
userID = 12
AND id IN (SELECT articleID FROM favourites WHERE articlesUserID = 12)
ORDER BY postdate DESC;
this is the format my query has right now in cakePHP :
$favouritearticles = $this->Favourite->query('SELECT id, title, author, postdate, postdatecreation, posteditdate, postcontent, "userID" FROM posts WHERE "userID" = '.$userID.'AND id IN (SELECT lngblogarticleid FROM favourites WHERE lngloginuserid = '.$userID.') ORDER BY postdate DESC');
It's working but if echo json_encode the result like this :
echo json_encode($favouritearticles);
I get an invalid json format like the following :(checked with JSONLint)
[
[
{
"id": 2,
"title": "Prison Or Treatment For the Mentally ill ",
"author": "mike123",
"postdate": "March 12, 2013 at 6:46 pm",
"postdatecreation": "2013-03-12",
"posteditdate": null,
"postcontent": "<p><span>The public revulsion over repeated mass shootings has placed mental health in the spotlight. This is both good and bad.<\/span><\/p>",
"userID": 34
}
]
][
]
So I thought that maybe I should rewrite my query using cakePHP format "using find method" something like :
$favouritearticles = $this->Favourite->find('all',array('conditions'=>array(".........
however the query is quite complex and I don't see how to do so.
Thank you for any help.

Format of JSON is fine except for extra [ ] at the end.
If you still want to rewrite the query in CakePHP format, use following:
private function getFavouritePostsByUserId($userId) {
$db = $this->Post->getDataSource();
$subQuery = $db->buildStatement(
array(
'fields' => array('Favourite.articleID'),
'table' => $db->fullTableName($this->Favourite),
'alias' => 'Favourite',
'conditions' => array(
'Favourite.articlesUserID' => $userId
),
),
$this->Favourite
);
$subQuery = 'Post.id IN (' . $subQuery . ') ';
$subQueryExpression = $db->expression($subQuery);
$conditions = array($subQueryExpression, 'Post.userID' => $userId);
$fields = array('Post.*');
$order = 'Post.postdate DESC';
$this->Post->find('all', compact('conditions', 'fields', 'order'));
}

Related

Stumped on this little SQL query

This SQL query is currently returning all values with the word anywhere in it. For instance, typing Mon will return Armoring, Behemoth, Emotion, etc etc. I'd like it to return words that start with the value, like, Monkey, Moment, Monday, etc.
Hope my explanation makes sense, code is below.
function action_ajax_drug_suggest() {
global $wpdb;
if ( empty( $_GET['term'] ) ) {
die();
}
$drug_name = $wpdb->esc_like( $_GET['term'] );
$table = $wpdb->prefix . self::TABLE_DRUG;
$posts = $wpdb->get_results( $wpdb->prepare( "
SELECT name
FROM {$table}
WHERE name LIKE '%%%s%%'
AND details <> ''
LIMIT 5",
$drug_name ) );
foreach( $posts as $post ) {
$names[] = array(
'label' => $post->name,
);
}
wp_send_json( $names );
}
try leaving out the first two %% signs
LIKE '%%%s%%' becomes LIKE '%s%%'

Perl SQL::Parser table alias substitution: works for SELECT column names but not for WHERE column names

I'm trying to parse some SQL queries stored in a log database -- I don't want to submit them to a SQL database, just to extract the fields used in the SELECT and WHERE clause.
I've been fiddling with several SQL parsers in Java, Python and Perl. The one that seems to work better for my problem are SQL::Parser and SQL::Statement. With those I was able to write the following code:
#!/usr/bin/perl
use strict;
use SQL::Parser;
use SQL::Statement;
use Data::Dumper;
my $sql = "SELECT sl.plate,sp.fehadop FROM sppLines AS sl ".
"JOIN sppParams AS sp ON sl.specobjid = sp.specobjid ".
"WHERE fehadop < -3.5 ";
my $parser = SQL::Parser->new();
my $stmt = SQL::Statement->new($sql,$parser);
printf("COMMAND [%s]\n",$stmt->command);
printf("COLUMNS \n");
my #columns = #{$stmt->column_defs()};
foreach my $column ( #columns)
{
print " ".$column->{value}."\n";
}
printf("TABLES \n");
my #tables = $stmt->tables();
foreach my $table ( #tables)
{
print " ".$table->{name}."\n";
}
printf("WHERE COLUMNS\n");
my $where_hash = $stmt->where_hash();
print Dumper($where_hash);
Sorry if it is too long, it is the smallest, self-contained example I could devise.
The output of this code is:
COMMAND [SELECT]
COLUMNS
spplines.plate
sppparams.fehadop
TABLES
spplines
sppparams
WHERE COLUMNS
$VAR1 = {
'arg1' => {
'value' => 'fehadop',
'type' => 'column',
'fullorg' => 'fehadop'
},
'op' => '<',
'nots' => {},
'arg2' => {
'str' => '-?0?',
'fullorg' => '-3.5',
'name' => 'numeric_exp',
'value' => [
{
'fullorg' => '3.5',
'value' => '3.5',
'type' => 'number'
}
],
'type' => 'function'
},
'neg' => 0
};
The parser returns the name of columns (obtained through a call to $stmt->column_defs()) already renamed with the real tables names (e.g. spplines.plate instead of s1.plate) -- this is what I want.
I also want the names of the columns used in the WHERE clause.
I already know how to recursively parse the results of $stmt->where_hash() (didn't include the code to make the post clear), but even from dumping its contents I can see that the column names are not associated with the tables.
I would like to ensure that the columns names in the WHERE clause are also preceded by the tables name. After parsing the results of $stmt->where_hash() I would get sppparams.fehadop instead of fehadop.
Is this possible with SQL::Parser?
Thanks
(big edit -- tried to make the question clearer)
Since SQL::Statement has an eval_where, I suspect there might be a better way, but you can try a function like this:
get_column($stmt->column_defs(), $where_hash->{arg1});
sub get_column {
my ($columns, $arg) = #_;
return $arg->{fullorg} if ($arg->{type} ne 'column');
foreach my $col (#$columns) {
return $col->{value} if ($col->{fullorg} eq $arg->{fullorg});
my ($name) = ( $col->{fullorg} =~ /([^.]+)$/);
return $col->{value} if ($name eq $arg->{fullorg});
}
return $arg->{fullorg};
}

Doctrine QueryBuilder multiple distinct

I would like to restrict results with DISTINCT on two columns using doctrine ORM
My function is like this :
public function findFdvLinkedToPdv($pointVenteCodes){
$queryBuilder =
$this->createQueryBuilder('r')
->leftJoin('r.forceVente', 'forceVente')
->leftJoin('r.pointVente', 'pointVente')
->leftJoin('r.signature', 'signature')
->leftJoin('signature.affaire', 'affaire')
->andWhere('pointVente.code IN (:pointvente_codes)')
->orderBy('forceVente.matricule', 'ASC')
->addOrderBy('pointVente.code', 'ASC')
->addOrderBy('affaire.code', 'ASC')
->addOrderBy('r.type', 'ASC')
->setParameters(array('pointvente_codes' => $pointVenteCodes,))
->select(array(
'forceVente.matricule AS forcevente_matricule',
'pointVente.code AS pointvente_code',
'affaire.code AS affaire_code',
'r.id AS id',
'r.profil AS profil',
'r.type AS type',
'forceVente.nom AS nom',
'forceVente.prenom AS prenom',
'forceVente.email AS email',
'r.deletedAt AS deletedAt'));
return $queryBuilder->getQuery()->getArrayResult();
}
For each forcevente.matricule and each pointVente.code , I have from 2 to 6 rows. I would like to get one row for each couple forcevente.matricule/pointVente.code I have to do a distinct on both columns, but when I try :
->select(array(
'DISTINCT forceVente.matricule AS forcevente_matricule',
'DISTINCT pointVente.code AS pointvente_code',
'affaire.code AS affaire_code', etc ...
I have a doctrine error ...
[EDIT]
I do this in PHP after executing the request to filter the results...
//BEGIN PATCH
$i=0;
$linkedForceVentes2 = array();
foreach ($linkedForceVentes as $item) {
if (!isset($linkedForceVentes2[$item['pointvente_code']][$item['forcevente_matricule']])){
$linkedForceVentes2[$item['pointvente_code']][$item['forcevente_matricule']] = $item;
}else{
unset($linkedForceVentes[$i]);
}
$i++;
}
//END PATCH
I finaly resolved it with a groupBy :
->groupBy('forcevente_matricule', 'pointvente_code', 'type' , 'affaire_code');
Just after the select statement.

How to return a JSON array from sql table with PhalconPHP

I have several tables that have JSON arrays stored within fields.
Using PHP PDO I am able to retrieve this data without issue using:
$query1 = $database->prepare("SELECT * FROM module_settings
WHERE project_token = ? AND module_id = ? ORDER BY id DESC LIMIT 1");
$query1->execute(array($page["project_token"], 2));
$idx = $query1->fetch(PDO::FETCH_ASSOC);
$idx["settings"] = json_decode($idx["settings"]);
This returns a string like:
{"mid":"","module_id":"1","force_reg_enable":"1","force_reg_page_delay":"2"}
Attempting to gather the same data via PhalconPHP
$result = Modulesettings::findFirst( array(
'conditions' => 'project_token = "' . $token . '"' ,
'columns' => 'settings'
) );
var_dump($result);
Provides a result of
object(Phalcon\Mvc\Model\Row)#61 (1) { ["settings"]=> string(167) "{"text":"<\/a>
<\/a>
","class":""}" }
What do I need to do different in Phalcon to return the string as it is stored in the table?
Thank you.
You have 2 approach
First :
Get the settings with this structure :
$settings = $result->settings;
var_dump($settings);
Second :
First get array from resultset, then using the array element :
$res = $result->toArray();
var_dump($res['settings']);
Try it.
You can decode json right in your Modulesettings model declaration:
// handling result
function afterFetch() {
$this->settings = json_decode($this->settings);
}
// saving. Can use beforeCreate+beforeSave+beforeUpdate
// or write a Json filter.
function beforeValidation() {
$this->settings = json_encode($this->settings);
}

Laravel 5: Join On with IN query

I'm trying to do something like:
$results = $query->leftJoin('checklist_items', function($join) use ($days) {
$join->on('users.id', '=', 'checklist_items.user_id')
->on('checklist_items.due_date', 'IN', $days);
})
->where('checklist_items.user_id', null)
->limit(10)
->get();
This is an example of the query I'm attempting to execute:
SELECT *
FROM users
LEFT JOIN checklist_items
ON users.id = checklist_items.user_id
AND checklist_items.due_date IN ('2015-07-09', '2015-07-10')
WHERE checklist_items.user_id IS NULL
ORDER BY users.id
So this is a left outer join. In query builder, most of this is no problem. The problem is the fact that my AND line uses an IN query. If it were part of a WHERE clause I would use ->whereIn but since I need it in the Join clause, whereIn won't work and there is no orIn or some such.
Suggestions?
You can use ->whereIn() within the ->leftJoin() closure (Tested in Laravel 5.7.16):
$days = ['2015-07-09', '2015-07-10'];
$results = \DB::table('users')
->leftJoin('checklist_items', function($join) use ($days) {
$join->on('users.id', '=', 'checklist_items.user_id')
->whereIn('checklist_items.due_date', $days);
})
->where('checklist_items.user_id', null)
->orderby('users.id')
->get();
Output from dd(\DB::getQueryLog(); produces your example query:
array:1 [▼
0 => array:3 [▼
"query" => "select * from `users` left join `checklist_items` on `users`.`id` = `checklist_items`.`user_id` and `checklist_items`.`due_date` in (?, ?) where `checklist_items`.`user_id` is null order by `users`.`id` asc ◀"
"bindings" => array:2 [▼
0 => "2015-07-09"
1 => "2015-07-10"
]
"time" => 6.97
]
]
I think you would need to use DB::raw() so it doesn't try to quote your days and wrap your days in parenthesis as well. This should do the trick.
$days = '(\'2015-07-09\', \'2015-07-10\')';
$results = DB::table('users')->leftJoin('checklist_items', function($join) use ($days) {
$join->on('users.id', '=', 'checklist_items.user_id')
->on('checklist_items.due_date', 'IN', DB::raw($days));
})
->where('checklist_items.user_id', null)
->limit(10)
->toSql();
echo $results;
This Query will Work
$results = DB::table('users')
->join('checklist_items','checklist_items.user_id','=','users.id')
->whereIn('checklist_items.due_date',['2015-07-09', '2015-07-10'])
->whereNull('checklist_items.user_id')
->orderBy('users.id','asc')
For Laravel 7 and above use whereIn instead of on :
$join->on('users.id', '=', 'checklist_items.user_id')
->whereIn('checklist_items.due_date',$days);