I've been tasked with converting all MySQL queries to PDO. This has been fine, until this one query which doesn't work as expected in PDO form.
The MySQL version of the query, which works fine, is:
$queryPages = "SELECT m.member_id, p.page_id, p.live, p.version, p.page_title, p.page_locked_for_editing, p.form, p.folder_main_page, p.expire_date, DATE_FORMAT(p.published_date, '$DATESQL') AS published_date, p.author_id, m.firstname, m.surname FROM pages AS p LEFT JOIN members AS m ON m.member_id = p.author_id WHERE p.folder_id = '$folder_id' ORDER by p.folder_main_page DESC, p.page_id DESC";
$resultPages=mysqli_query(db_connect(), $queryPages);
The PDO version I've created is:
$sql = "SELECT m.member_id, p.page_id, p.live, p.version, p.page_title, p.page_locked_for_editing, p.form, p.folder_main_page, p.expire_date, DATE_FORMAT(p.published_date, ?) AS published_date, p.author_id, m.firstname, m.surname FROM pages AS p LEFT JOIN members AS m ON m.member_id = p.author_id WHERE p.folder_id = ? ORDER by p.folder_main_page DESC, p.page_id DESC";
$stmt = $dbh->prepare($sql);
$resultPages = $stmt->execute([$DATESQL, $folder_id]);
I'm guessing it's something to do with the DATE_FORMAT part, but not sure how it needs to be changed.
Related
I'd like to get all queries run by users in a specific user group for a Redshift database.
I'm getting warning - Column "g.grolist" has unsupported type "integer[]".
I've tried other forms of the same query (e.g., putting the ANY condition in WHERE), but I keep getting the same error.
How can I check whether a user ID occurs in the list of user IDs in pg_group?
Please note that grolist values are like this-
{266,267,265}
Here's the query I'm running:
select
q.*,
u.usename,
swq.total_queue_time / 1000000 as queue_time
from stl_query q
inner join pg_user u on q.userid = u.usesysid
inner join pg_group g on u.usesysid = ANY (g.grolist)
inner join stl_wlm_query swq on q.query = swq.query
where q.userid <> 1
AND database = 'mydb'
AND g.groname = 'ops'
order by q.starttime desc;`
u.usesysid is an integer whereas g.grolist is an integer[]. operator does not exist: integer = integer[];
SELECT *,
SUM(num_hr) AS total_hr,
attendances.empID AS empid
FROM attendances
LEFT JOIN addsalaryemployees
ON addsalaryemployees.empID = attendances.empID
LEFT JOIN positions
ON positions.id = addsalaryemployees.empPosition
GROUP BY attendances.empID
ORDER BY addsalaryemployees.empFirstName ASC
The Laravel documentation is pretty good, there is an entire section on the Query Builder which I recommend you take a read through.
There are a few ways you could achieve your desired SQL, the following being just one.
$query = DB::table('attendances')
->leftJoin('addsalaryemployees', 'addsalaryemployees.empID', '=', 'attendances.empID')
->leftJoin('positions', 'positions.id', '=', 'addsalaryemployees.empPosition')
->groupBy('attendances.empID')
->orderBy('addsalaryemployees.empFirstName')
->selectRaw('*, SUM(num_hr) AS total_hr, attendances.empID AS empid');
If you dd($query->toSql()), you'll get the following.
select *, SUM(num_hr) AS total_hr, attendances.empID AS empid
from `attendances`
left join `addsalaryemployees` on `addsalaryemployees`.`empID` = `attendances`.`empID`
left join `positions` on `positions`.`id` = `addsalaryemployees`.`empPosition`
group by `attendances`.`empID`
order by `addsalaryemployees`.`empFirstName` asc
I've been trying for hours now but everytime i create a DQL query with a subquery, it seems to add an ORDER BY to the end that should be apart of the subquery even though i haven't explicitly asked for an ORDER BY.
Here's my DQL:
Doctrine_Query::create()
->select('r.*')
->from($table->getTableName() . ' r')
->innerJoin('r.Product p')
->where('r.is_published = 1')
->andWhere('NOT EXISTS (
SELECT pm.product_id
FROM ProductMedia pm
WHERE pm.product_id = p.id
)');
and heres the resulting query:
SELECT r.id AS r__id, r.created_sf_guard_user_id AS r__created_sf_guard_user_id, r.author_id AS r__author_id, r.published_at AS r__published_at, r.teaser_web AS r__teaser_web, r.teaser_newsletter AS r__teaser_newsletter, r.verdict AS r__verdict, r.product_id AS r__product_id, r.award_recommended AS r__award_recommended, r.award_editors_choice AS r__award_editors_choice, r.with_photos_tab AS r__with_photos_tab, r.first_look AS r__first_look, r.review_type AS r__review_type, r.overall_score AS r__overall_score, r.comments_id AS r__comments_id, r.review_price AS r__review_price, r.reviewed_at AS r__reviewed_at, r.adtech_keywords AS r__adtech_keywords, r.last_synced AS r__last_synced, r.standout_url AS r__standout_url, r.show_on_homepage AS r__show_on_homepage, r.best_deals_copy AS r__best_deals_copy, r.preview_to_review_at AS r__preview_to_review_at, r.created_at AS r__created_at, r.updated_at AS r__updated_at, r.is_published AS r__is_published, r.publish_start AS r__publish_start, r.publish_end AS r__publish_end FROM review r INNER JOIN product p ON r.product_id = p.id WHERE (r.is_published = 1 AND (NOT (EXISTS (SELECT p2.product_id AS p2__product_id FROM product_media p2 WHERE (p2.product_id = p.id))))) ORDER BY p2.position ASC
This is very strange behaviour and not sure whats causing it.
Any help is appreciated and if I'm missing anything to help please ask and i'll edit the question.
Thanks.
Ok, so I have this Concern which contains a method top for retrieving records order by the number of times someone has listened to them (directly if the record is a song, or via songs if it's something else, like a genre or artist). In case of a tie, it orders records by the popularity on other sites.
The following code works almost perfectly. It returns an array of the objects, in the correct order. My main issue is that I get an array and not a relation. So the caller cannot further add stuff like Song.top.limit 3 or Genre.top.offset(10).limit(5).
Here's my method:
def top(options = {})
tname = self.name.tableize
inner_select = self.select("#{tname}.*,COUNT(DISTINCT(listens.id)) AS listens_count")
inner_select = inner_select.joins(:songs) unless self.name == 'Song'
inner_select = inner_select.joins("LEFT JOIN listens ON listens.song_id = songs.id")
inner_select = inner_select.where("listens.user_id = ?", options[:for].id) if options[:for].is_a? User
inner_select = inner_select.group("#{tname}.id").to_sql
# this is the part that needs fixin'
find_by_sql("
SELECT
#{tname}.*,
#{tname}.listens_count,
SUM(sources.popularity) AS popularity_count
FROM (#{inner_select}) AS #{tname}
LEFT JOIN sources ON
sources.resource_id = #{tname}.id
AND
sources.resource_type = '#{self.name}
GROUP BY #{tname}.id
ORDER BY listens_count DESC, popularity_count DESC
")
end
Here are the SQL queries that are generated, as requested. This is from Song.top:
SELECT
songs.*,
songs.listens_count,
SUM(sources.popularity) AS popularity_count
FROM (SELECT songs.*,COUNT(DISTINCT(listens.id)) AS listens_count FROM "songs" LEFT JOIN listens ON listens.song_id = songs.id GROUP BY songs.id) AS songs
LEFT JOIN sources ON
sources.resource_id = songs.id
AND
sources.resource_type = 'Song'
GROUP BY songs.id
ORDER BY listens_count DESC, popularity_count DESC
This is from Artist.top:
SELECT
artists.*,
artists.listens_count,
SUM(sources.popularity) AS popularity_count
FROM (SELECT artists.*,COUNT(DISTINCT(listens.id)) AS listens_count FROM "artists" INNER JOIN "artists_songs" ON "artists_songs"."artist_id" = "artists"."id" INNER JOIN "songs" ON "songs"."id" = "artists_songs"."song_id" LEFT JOIN listens ON listens.song_id = songs.id GROUP BY artists.id) AS artists
LEFT JOIN sources ON
sources.resource_id = artists.id
AND
sources.resource_type = 'Artist'
GROUP BY artists.id
ORDER BY listens_count DESC, popularity_count DESC
So I found the answer, turns out I had completely missed the from method. I'll post the final method here just in case anyone else is as blind as me:
def top(options = {})
tname = self.name.tableize
inner_select = self.select("#{tname}.*,COUNT(DISTINCT(listens.id)) AS listens_count").
joins("LEFT JOIN listens ON listens.song_id = songs.id").
group("#{tname}.id")
inner_select = inner_select.joins(:songs) unless self.name == 'Song'
inner_select = inner_select.where("listens.user_id = ?", options[:for].id) if options[:for].is_a? User
inner_select = "(#{inner_select.to_sql}) as #{tname}"
select("#{tname}.*,#{tname}.listens_count,SUM(sources.popularity) AS popularity_count").
from(inner_select).
joins("LEFT JOIN sources ON sources.resource_id = #{tname}.id AND sources.resource_type = '#{self.name}'").
group("#{tname}.id").
order("listens_count DESC, popularity_count DESC")
end
I am using a wordpress plugin called "kf most read" which stores a count of how many times a post was read, and lets you output a list of most read posts.
This works well. The issue is, I am trying to pull the most read posts, but only the most read posts within the current category you are viewing.
I am close to clueless when it comes to sql.
Here us what the plugin is currently using to pull the most read posts:
$sql = "SELECT count(mr.post_ID) as totHits, p.ID, p.post_title from $wpdb->posts p JOIN {$wpdb->prefix}kf_most_read mr on mr.post_ID = p.ID where mr.hit_ts >= '".(time() - ( 86400 * $period))."' GROUP BY mr.post_ID order by totHits desc, ID ASC LIMIT $limit";
How could I incorporate the below query which pulls from a specific category into the above?
$sql .= "LEFT JOIN $wpdb->term_taxonomy ON($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)" ;
$sql .= "WHERE $wpdb->term_taxonomy.term_id IN ($currentcat)" ;
$sql .= "AND $wpdb->term_taxonomy.taxonomy = 'category'" ;
Any Help on this would be much appreciated.
You need to merge the from + join sections together, and the where clauses together. Your original query is
SELECT count(mr.post_ID) as totHits, p.ID, p.post_title
-- from & join
FROM $wpdb->posts p
JOIN {$wpdb->prefix}kf_most_read mr
ON mr.post_ID = p.ID
-- where
WHERE mr.hit_ts >= '".(time() - ( 86400 * $period))."'
-- group, etc.
GROUP BY mr.post_ID
ORDER BY totHits desc, ID ASC LIMIT $limit
and your extra clauses
-- from & join
LEFT JOIN $wpdb->term_taxonomy
ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
-- where
WHERE $wpdb->term_taxonomy.term_id IN ($currentcat)
AND $wpdb->term_taxonomy.taxonomy = 'category'
so the merged query should be
SELECT count(mr.post_ID) as totHits, p.ID, p.post_title
-- from & join
FROM $wpdb->posts p
JOIN {$wpdb->prefix}kf_most_read mr
ON mr.post_ID = p.ID
LEFT JOIN $wpdb->term_taxonomy
ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
-- where
WHERE mr.hit_ts >= '".(time() - ( 86400 * $period))."'
AND $wpdb->term_taxonomy.term_id IN ($currentcat)
AND $wpdb->term_taxonomy.taxonomy = 'category'
-- group, etc.
GROUP BY mr.post_ID
ORDER BY totHits desc, ID ASC LIMIT $limit
(NB you can only have one where so the adding the second as an and)
i.e. something like
$sql = "SELECT count(mr.post_ID) as totHits, p.ID, p.post_title FROM $wpdb->posts p"
$sql .= " JOIN {$wpdb->prefix}kf_most_read mr ON mr.post_ID = p.ID"
$sql .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)"
$sql .= " WHERE mr.hit_ts >= '".(time() - ( 86400 * $period))."'"
$sql .= " AND $wpdb->term_taxonomy.term_id IN ($currentcat)"
$sql .= " AND $wpdb->term_taxonomy.taxonomy = 'category'"
$sql .= " GROUP BY mr.post_ID ORDER BY totHits desc, ID ASC LIMIT $limit"
depending on how you like your line-breaks. Hope that works!
Actually I suspect you don't really want a LEFT JOIN for the categories / taxonomy table but should have a plain JOIN instead. But I'm no WP schema expert.