wordpress query filtering by custom-field, tag and category - custom-fields

i have made this query to select posts from a WordPress blog filtering by Category, Tag and Custom Fields.
SELECT wp_posts.*
FROM wp_posts
WHERE wp_posts.post_type = 'post' AND wp_posts.post_status = 'publish'
AND ( SELECT COUNT(*)
FROM wp_term_relationships
LEFT JOIN wp_term_taxonomy ON ( wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
LEFT JOIN wp_terms ON ( wp_term_taxonomy.term_id = wp_terms.term_id )
WHERE wp_posts.ID = wp_term_relationships.object_id
AND ( wp_terms.name = 'collaborazioni' && wp_term_taxonomy.taxonomy = 'category' )
||
( wp_terms.name = 'jammin' && wp_term_taxonomy.taxonomy = 'post_tag' )
) >= 1
AND ( SELECT COUNT(*) FROM wp_postmeta
WHERE wp_postmeta.post_id = wp_posts.ID
AND wp_postmeta.meta_key = 'Product-code'
AND wp_postmeta.meta_value = 'xxxxxx'
) >= 1
but i think that is a little heavy .. did you have some better solution ?
thanks, Pietro.

What exactly would you like to make shorter? It already looks shorten pretty well.
PS. You might want to use {$wpdb->prefix} instead of wp_ in queries.

Related

Rails find_by_SQL with Rails

I'm using a find_by_sql method to search users in my userstable.
is there a possibility to use rails code in the select statement?
User.find_by_sql ["SELECT DISTINCT
users.*
FROM
users
JOIN
clients_courses cc
ON
cc.client_id = users.client_id
LEFT JOIN
memberships m
ON
m.user_id = users.id AND m.course_id = cc.course_id
WHERE
cc.course_id = ?
AND
m.user_id IS NULL
AND
users.active = ?
AND
users.firstname LIKE ? or users.lastname LIKE ?
AND NOT IN ( RAILS CODE )", self.id, true, "#{search}%", "#{search}%"]
end
I Marked the position with RAILS CODE
I want to do someting linke this:
Membership.where("course_id = ?", self.id).users
is there a way to do this?
You can do this -
member_user_ids = []
Membership.where("course_id = ?", self.id).map{|membership| membership.users.map{|user| member_user_ids << user.id}}
# you might want to put a uniq! on member_user_ids
User.find_by_sql ["SELECT DISTINCT
users.*
FROM
users
JOIN
clients_courses cc
ON
cc.client_id = users.client_id
LEFT JOIN
memberships m
ON
m.user_id = users.id AND m.course_id = cc.course_id
WHERE
cc.course_id = ?
AND
m.user_id IS NULL
AND
users.active = ?
AND
users.firstname LIKE ? or users.lastname LIKE ?
AND users.id NOT IN ( #{member_user_ids.join(',')} )", self.id, true, "#{search}%", "#{search}%"]
You can also have a look at link which explains how to put array of strings in where clause.

Rails: Search for person with language skills - e,g, speaks "German AND English" on one-to-many table

This must be a basic thing in rails, but I don't know how to do it.
I would like to filter participants based on the languages they speak. People can speak multiple languages, and languages are stored in their own table with a one-to-many relationship.
Now my search looks really clunky and doesn't seem to work:
if #cvsearch.language.present? == true and #cvsearch.language != 0
#p = #p.joins(:languages).where('languages.name = ?', #cvsearch.language)
else
#cvsearch.language = 0
end
if #cvsearch.language1.present? == true and #cvsearch.language1 != 0
#p = #p.joins(:languages).where('languages.name = ?', #cvsearch.language1)
end
if #cvsearch.language2.present? == true and #cvsearch.language2 != 0
#p = #p.joins(:languages).where('languages.name = ?', #cvsearch.language2)
end
if #cvsearch.language3.present? == true and #cvsearch.language3 != 0
#p = #p.joins(:languages).where('languages.name = ?', #cvsearch.language3)
end
The resulting SQL, slightly shortened:
SELECT COUNT(*) FROM "participants" INNER JOIN "languages" ON "languages"."participant_id" = "participants"."id" WHERE (participants.id >= 2) AND (languages.name = 11) AND (languages.name = 10)[0m
It would be great to get a specific solution, but even better is a pointer as to where I can read up on this - what's the key word I am missing to describe this problem?
So this is the solution I am using for now:
if #cvsearch.language1.present? == true and #cvsearch.language1 != 0
safe_lang = ActiveRecord::Base::sanitize(#cvsearch.language1)
qry = "INNER JOIN languages l1 ON l1.participant_id = participants.id AND l1.name = " + safe_lang.to_s
#p = #p.joins(qry)
end
Works wonderfully, just need to get some feedback regarding the safety of this approach.
I'm not sure of a general reference to refer you to, but this is basic SQL stuff. Basically, the JOIN is performed first resulting in a number of rows and then the WHERE is applied, filtering the rows. The conceptual mistake here is thinking that the WHERE clause will somehow apply to the full set of matched languages, but it doesn't work that way, each row of the result is considered in isolation, therefore a clause like (languages.name = 11) AND (languages.name = 10) will never return anything, because languages.name only has a single value in each row. The query as constructed could only work for an OR clause, so you could say something like WHERE (languages.name = 11) OR (languages.name = 12).
In order to filter down the participants you need one join for each language, so you want something like this:
SELECT COUNT(*) FROM participants
INNER JOIN languages l1 ON l1.participant_id = participants.id AND (languages.name = 10)
INNER JOIN languages l2 ON l2.participant_id = participants.id AND (languages.name = 11)
WHERE participants.id >= 2
Offhand I'm not sure of the easiest way to do this in ActiveRecord, it's not a super common query. Your general structure should work, but with something like:
if #cvsearch.language1.present? == true and #cvsearch.language1 != 0
safe_language = ActiveRecord::Base.sanitize(#cvssearch.language1)
join_clause = "INNER JOIN languages l1 ON l1.participant_id = participants.id AND language.name = #{safe_language}"
#p = #p.joins(join_clause)
end

How to use multiple on clause in joining in zend framework 2

I am doing like this sql into zend framework sql pattern.
SELECT
jobs . *,
c.id AS cid,
c.name AS name,
c.companyImage AS companyImage,
c.logo AS logo,
count(app.userId) AS t_app,
app.applyStatus AS applyStatus,
app.userId AS appUserId
FROM
jobs
LEFT JOIN
companies AS c ON jobs.companyName = c.id
LEFT JOIN
applicants AS app ON jobs.id = app.jobId AND app.applyStatus = 1
WHERE
jobs.ownerId = 16 AND jobs.draftId != 0
GROUP BY jobs.id
ORDER BY jobs.id DESC
LIMIT 3
For this sql I already write this code for zend framework 2
$adapter = $this->tableGateway->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('jobs')
->join(array('c' => 'companies'), 'jobs.companyName = c.id', array('cid' => 'id', 'name', 'companyImage', 'logo'), 'left')
->join(array('app' => 'applicants'), ' jobs.id = app.jobId AND app.applyStatus = 1', array('t_app' => new Expression('count(app.userId)'), 'applyStatus', 'appUserId' => 'userId'), 'left')
->where("jobs.ownerId ={$userId} AND jobs.draftId != 0")
->group('jobs.id')
->order('jobs.id DESC')
->limit(3);
$statement = $sql->getSqlStringForSqlObject($select);
$results = $adapter->query($statement, $adapter::QUERY_MODE_EXECUTE);
but does not work properly and its give a message like below.
SQLSTATE[42S22]: Column not found: 1054 Unknown column '1' in 'on clause'
The issue is this part:
app.applyStatus = 1
The framework is escaping 1 as if it were a column name, 1.
You need to enclose this part in an Expression too
new Expression('jobs.id = app.jobId AND app.applyStatus = 1')
I think the use of Expressions in the 'ON' parameter of the join method may depend on the version of ZF2 you are using, I think it was added 2.1+
Building on this answer. If you also want your table & column identifiers to be escaped, use this syntax:
use Zend\Db\Sql\Expression;
...
$onExpression = new Expression('? = ? AND ? = ?',
['jobs.id', 'app.jobId', 'app.applyStatus', 1],
[Expression::TYPE_IDENTIFIER, Expression::TYPE_IDENTIFIER,
Expression::TYPE_IDENTIFIER, Expression::TYPE_LITERAL]
);
$select->from('jobs')
->join(array('app' => 'applicants'), $onExpression, array('t_app' => new Expression('count(app.userId)'), 'applyStatus', 'appUserId' => 'userId'), 'left');
The Expression constructor accepts the string, then arguments, then argument types.
public function __construct($expression = '', $parameters = null, array $types = [])
This will create a security issue. Zf2 changes your query to this:
Select * from tableA inner join tableB
on `tableA`.`column` = `tableB`.`column`
AND `tableB`.`column` = `1`
It adds
`
to each part for security issues! By using new Expression you are bypassing it and if you get applyStatus from user entry, get sure about its filtering!

Speeding up a linq query

I am trying to replicate the following SQL query with linq. On SQL Server it takes a fraction of a second to run:
select g.reference, count(*)
from isis.dbo.[group] as g inner join
isis.dbo.enrolment as e on g.groupid = e.groupid inner join
isis.dbo.student as s on e.studentid = s.studentid inner join
isis.dbo.progression as p on s.studentid = p.studentid
where p.academicyear = '12/13' and g.istutorgroup = 1
group by reference
In my MVC application I am passing a listing of "TutorGroups" to the view. For each tutor group in the view I need to display various information about them, one item being the number of "Progression" interviews they have had.
I have tried a couple of methods but they both take upwards of 30 secs to run in my MVC application:
<%TTMrequired = tg.Enrolments
.SelectMany(e => e.Student.Progressions
.Where(p => p.TTMChecked == false &&
p.TTMInterview == true &&
p.AcademicYear == year))
.Count(); %>
and
<%TTMrequired = tg.Enrolments
.Where(e => e.Student.Progressions
.Any(p => p.TTMChecked == false &&
p.TTMInterview == true &&
p.AcademicYear == year))
.Count(); %>
Anyone got any suggestions on how I can speed this up? I suspect the problem is me trying to do it a stupid way - it usually is!
You could try doing a Sum of counts instead of a SelectMany:
tg.Enrolments.Sum(e => e.Student.Progressions
.Count(p => p.TTMChecked == false &&
p.TTMInterview == true &&
p.AcademicYear == year)
);
Should be written using this syntax:
var TTMRequired = (from g in tg.Groups
join e in tg.Enrolment on g.groupid equals e.groupid
join s in tg.Students on e.studentid equals s.studentid
join p in tg.Progressions on s.studentid = p.studentid
where p.academicyear.Equals("12/13") && g.istutorgroup.Equals(1)
group g by g.reference into grp
select new {
grpRef = grp.Key,
grpCount = grp.Count()
});
Note: if g.istutorgroup is of type BIT instead of INT, consider using .Equals(true).

Rails Nested Query

I have follow query
notes = Note.where('notes.id IN
(
SELECT "notes"."id" FROM "notes"
WHERE "notes"."circle_id" = ?
)
OR notes.id IN
(
SELECT "notes"."id" FROM "notes"
INNER JOIN "circles_dreams"
ON "circles_dreams"."dream_id" = "notes"."dream_id"
WHERE "circles_dreams"."circle_id" = ?
)', #circle.id, #circle.id)
How to simplify this query?
Thanks.
First of all you can collect all needed notes id.
I supposed to think what you already have relations between Note and CirclesDream
note_ids = Note.where(circle_id: #circle.id).pluck(:id) # your first SELECT
dream_ids = CirclesDream.where(id: #circle.id).pluck(:note_id) # your second SELECT
notes_ids = note_ids | dreams_ids # combine them
notes = Note.where(id: notes_ids) # Now your
upd: I've just fixed typo. Changed id to note_id in second request
Try this
note_ids = Note.where('circle_id = ?', #circle.id).pluck(:id)
dream_note_ids = Note.joins(:circle_dreams).where('circle_dreams.circle_id = ?', #circle.id).plunk(:note_id)
notes_ids = note_ids | dream_note_ids
If your circle_dreams table can contain records having note_id = null, then you have to apply join. So i think this will work in your case....

Resources