Wordpress Mysql wpdb query duplicates despite using DISTINCT - mysql

I've already looked at all similar solved questions but I've not found the solution yet.
So In this wordpress there are houses and circuits (custom post types). A house can have several circuits attached (repeater custom field ). The query gets dinamically built to retrieve all houses associated to any circuit from a list of IDS.
This works, but it repeats a house when it has more than one circuit that matches. For example:
SELECT DISTINCT *
FROM reoask5_posts p
INNER JOIN reoask5_postmeta pm_ci ON p.ID = pm_ci.post_id
WHERE p.post_type = 'casa'
AND p.post_status = 'publish'
AND pm_ci.meta_key LIKE 'circuito|__|_ci' ESCAPE '|'
AND (pm_ci.meta_value = 194 OR pm_ci.meta_value = 189)
...retrieves houseA which has circuito_0_ci = 194 and retrieves two times houseB which has circuito_0_ci = 194 and circuito_1_ci = 189 associated.
So what should I modify to filter out duplicates? What I'm doing wrong?
UPDATE1: More info
The table schema for posts (p)
The table schema for postmeta (pm_ci)
Still doesn't work well. Selectin specific columns from post database does filter out duplicates. But it fails in looping through the results like a normal wordpress loop. Even if I select ALL the columns:
SELECT DISTINCT p.id, p.post_author, p.post_date, p.post_date_gmt, p.post_content, p.post_title, p.post_excerpt, p.post_status, p.comment_status, p.ping_status, p.post_password, p.post_name, p.to_ping, p.pinged, p.post_modified, p.post_modified_gmt, p.post_content_filtered, p.post_parent, p.guid, p.menu_order, p.post_type, p.post_mime_type, p.comment_count
It gives me errors:
Notice: Undefined property: stdClass::$ID in .... line 250
Notice: Undefined property: stdClass::$ID in .... line 251
// etc...
This the simplified php code that comes after defining the query. All of these calls fail when I select specific columns:
$total_posts= $wpdb->get_results($query);
foreach ($total_posts as $post){
$post->post_name;
get_permalink($post->ID);
$coordenadas = get_field( "coords", $post->ID);
// ...
}
If I add all the 4 columns from metaposts to the SELECT line:
... p.comment_count, pm_ci.meta_id, pm_ci.post_id, pm_ci.meta_key, pm_ci.meta_value
It still gives me errors when trying to use those functions, that work when I use SELECT *
And I don't know how would I be supposed to use group by in this case. Still learning.
UPDATE2: Found the solution
The reason for the errors was because SELECT DISTINCT p.id should read SELECT DISTINCT p.ID . The SQL query returned the ID in a case insensitive manner, storing it in key 'id' , but the wordpress functions need that key in capitals ('ID') in order to work.
Thank you!

Your using DISTINCT * . This means that if one value in any one column is different (from a different row) it will be shown.
What you should instead do, is write distinct followed by the specific columns your interested in.
So, if your only interested in the specific houses -
Example:
select distinct houses
FROM ...
Using your Format:
select distinct
p.post_type
FROM ...
You could also use GROUP BY to count the number of different circuits a house has.

Related

How to create mysql function

i have the following sql query
SELECT id,
title,
total_likes,
IFNULL(SELECT 1 FROM 'likedata' WHERE user_id=$UID AND post_id=posts.id)0) AS is_liked
FROM 'posts'
I want to create mysql function to make my query bit shorter,
i don't know how to wrap the second query into sql function and pass 2 variables ($UID and $PID) to function to make this query shorter and more understandable.
any help would be great, thanks in advance
This isn't a good use case for a function.
A more fluent way of expressing this in SQL would be to use a left outer join, e.g:
SELECT posts.id, posts.title, posts.total_likes,
(likedata.id IS NOT NULL) AS is_liked
FROM posts
LEFT JOIN likedata ON (
posts.id = likedata.post_id AND likedata.user_id = $UID
)
You can see this in action here.
You can actually simply use exists. MySQL treats booleans as numbers, so:
SELECT p.id, p.title, p.total_likes,
( EXISTS (SELECT 1 FROM likedata ld WHERE ld.post_id = p.id AND ld.user_id = $UID)
) as is_liked
FROM posts p;
This seems closest to your original intent.
#duskwuff's answer is also a typical way to approach this. There is a slight different, because duplicates in likedata would result in duplicate rows in the result set using a join.
For either form, you want an index on likedata(post_id, user_id). And if you are passing $UID in, you should be using parameterized queries.

Create a SUM of multiplication columns from distinct tables in Ruby on Rails [duplicate]

Tag.joins(:quote_tags).group('quote_tags.tag_id').order('count desc').select('count(tags.id) AS count, tags.id, tags.name')
Build query:
SELECT count(tags.id) AS count, tags.id, tags.name FROM `tags` INNER JOIN `quote_tags` ON `quote_tags`.`tag_id` = `tags`.`id` GROUP BY quote_tags.tag_id ORDER BY count desc
Result:
[#<Tag id: 401, name: "different">, ... , #<Tag id: 4, name: "family">]
It not return count column for me. How can I get it?
Have you tried calling the count method on one of the returned Tag objects? Just because inspect doesn't mention the count doesn't mean that it isn't there. The inspect output:
[#<Tag id: 401, name: "different">, ... , #<Tag id: 4, name: "family">]
will only include things that the Tag class knows about and Tag will only know about the columns in the tags table: you only have id and name in the table so that's all you see.
If you do this:
tags = Tag.joins(:quote_tags).group('quote_tags.tag_id').order('count desc').select('count(tags.id) AS count, tags.id, tags.name')
and then look at the counts:
tags.map(&:count)
You'll see the array of counts that you're expecting.
Update: The original version of this answer mistakenly characterized select and subsequent versions ended up effectively repeating the current version of the other answer from #muistooshort. I'm leaving it in it's current state because it has the information about using raw sql. Thanks to #muistooshort for pointing out my error.
Although your query is in fact working as explained by the other answer, you can always execute raw SQL as an alternative.
There are a variety of select_... methods you can choose from, but I would think you'd want to use select_all. Assuming the build query that you implicitly generated was correct, you can just use that, as in:
ActiveRecord::Base.connection.select_all('
SELECT count(tags.id) AS count, tags.id, tags.name FROM `tags`
INNER JOIN `quote_tags` ON `quote_tags`.`tag_id` = `tags`.`id`
GROUP BY quote_tags.tag_id
ORDER BY count desc')
See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html for information on the various methods you can choose from.

Syntax error in complex SQL Query condition

I am having some trouble with my sql statement.
Here is a picture of the relevant tables:
A product can be in multiple categories.
A single product can have multiple varietycategories (ie: size, color, etc)
a varietycategory can have multiple varietycategoryoptions (ie: small, medium, large)
the table searchcriteria.criterianame loosly relates to varietycategory.category
the table searchcriteriaoption.criteriaoption loosely relates to varietycategoryoption.descriptor.
I get the searchcriteria.criterianame and use that string as the value we want to match with varietycategory.category and we also have to get the various searchcriteriaoption.criteriaoption strings (for that searchcriteria.criterianame) and match that against varietycategoryoption.descriptor for that varietycategory.category.
Here is the sql:
SELECT DISTINCT categories.*, product.*
FROM (categories, product, product_category)
LEFT JOIN varietycategory ON varietycategory.productid = product.id
LEFT JOIN varietycategoryoption ON varietycategoryoption.varietycategoryid = varietycategory.id
WHERE product_category.categoryid=4
AND product.id=product_category.productid
AND categories.category_id=product_category.categoryid
AND (
(varietycategory.category = 'color' AND (varietycategoryoption.descriptor='red' OR varietycategoryoption.descriptor='blue'))
OR
(varietycategory.category = 'size' AND (varietycategoryoption.descriptor = 'small' OR varietycategoryoption.descriptor='medium'))
)
but I get an error:
Unknown column 'varietycategory.id' in 'on clause'
I have tried to figure out what I am doing wrong. I tried simplifying the query a bit (just to try and determine what part of the sql query was causing the problem) to only match the searchcriteria.category string with the varietycategory.category and the query returns the data set correctly.
Here is the working query (this query is simplified and insufficient):
SELECT DISTINCT categories.*, product.*
FROM (categories, product, product_category)
LEFT JOIN varietycategory ON varietycategory.productid = product.id
WHERE product_category.categoryid=4
AND product.id=product_category.productid
AND categories.category_id=product_category.categoryid
AND (varietycategory.category = 'color' OR varietycategory.category = 'size' OR varietycategory.category='shape');
But I also need to be able to match against the varietycategoryoptions as well.
Just to avoid confusion, I am only using searchcriteria to get the field category and use it as a string to match against the varietycategory.category
and I am only using searchcriteriaoption to get the field criteriaoption and use it as a string to match against varietycategoryoption.descriptor
Does anyone know what I am doing wrong with my 1st query?
Please do help as SQL is not expertise.
Thank you!
The error is at:
OR
(varietycategory.category = 'size' (varietycategoryoption.desciptor = 'small' OR varietycategoryoption.descriptor='medium'))
^
|
An operator (AND, OR) is missing here
This has nothing to do with the join syntax, by the way.
Do not mix implicit and explicit joins. Your query should look like:
SELECT DISTINCT c.*, p.*
FROM product_category pc join
categories c
on c.category_id = pc.categoryid join
product p
on p.id = pc.productid join
varietycategory vc
ON vc.productid = p.id
WHERE c.categoryid = 4 AND
vc.category in ('color', 'size', 'shape');
You probably don't need the distinct, but that depends on the data. The left join is unnecessary because you are filtering on the second table in the where.
A simple rule: Never use commas in the from clause. To help, MySQL has scoping rules that can cause queries to break when you mix implicit and explicit join syntax.
The problem was a misspelled field on the table varietycategory, which I named
vcid, when I almost always name my table primary key id's "id".

What's wrong with this mySQL query?

Consider following two tables:
tag_names (tag_id, tag_name)
tag_links (tag_id, image_id)
An image can have multiple tags, I want to select all tags for a specific image id.
I am trying following query, but it doesnt seem to select correctly (selects only one row), What is wrong with it?
SELECT tag_name
FROM tag_names
LEFT JOIN tag_links.tag_id = tag_names.tag_id
WHERE tag_links.image_id = $image_id
Edit: I'm using CodeIgniter Active record query, but I wrote in basic SQL format so that if someone is not fimiliar with CodeIgniter can help. However, this query works fine with simple mysql format (without using CodeIgniter) but strangely does not work with CodeIgniter, even there is no any problem with the syntax, it just selects one row.
Here is CodeIgniter Syntax:
$this->db->select('tag_name');
$this->db->from('tag_names');
$this->db->join('tag_links', 'tag_links.tag_id = tag_names.tag_id', 'left');
$this -> db -> where('tag_links.image_id', (int)$image_id);
$query = $this->db->get();
Try this:
SELECT tag_name
FROM tag_names
LEFT JOIN tag_links
ON tag_links.tag_id = tag_names.tag_id
WHERE tag_links.image_id = $image_id
IMHO you forgot to join table (properly with ON statement) you are using.
EDIT: I have 2 ideas how to get rid of the problem:
First:
Change the line with SELECT
$this->db->select('tag_names.tag_name');
Second:
Use select() function with complete query:
$this->db->select($query, false);
$this->db->select() accepts an optional second parameter. If you set
it to FALSE, CodeIgniter will not try to protect your field or table
names with backticks. This is useful if you need a compound select
statement.
from: http://codeigniter.com/user_guide/database/active_record.html#select
It seems that you have a syntax error (you forgot tag_links in JOIN clause). By the way in my opinion you don't need LEFT JOIN for this purpose otherwise you may get incorrect results.
SELECT tag_name
FROM
tag_names
JOIN tag_links ON tag_links.tag_id = tag_names.tag_id
WHERE tag_links.image_id = $image_id
SELECT tag_names.tag_name
FROM tag_links
LEFT JOIN tag_names.tag_id = tag_links.tag_id
WHERE tag_links.image_id = $image_id
tag_names is only going to have single entry for a given ID, which means your query will return a single result. You need to primarily select from tag_links and then join the name of the tag on top of it, so you correctly select from the table with the multiple entries.

MySQL COUNT() causing empty array() return

MySQL Server Version: Server version: 4.1.14
MySQL client version: 3.23.49
Tables under discussion: ads_list and ads_cate.
Table Relationship: ads_cate has many ads_list.
Keyed by: ads_cate.id = ads_list.Category.
I am not sure what is going on here, but I am trying to use COUNT() in a simple agreggate query, and I get blank output.
Here is a simple example, this returns expected results:
$queryCats = "SELECT id, cateName FROM ads_cate ORDER BY cateName";
But if I modify it to add the COUNT() and the other query data I get no array return w/ print_r() (no results)?
$queryCats = "SELECT ads_cate.cateName, ads_list.COUNT(ads_cate.id),
FROM ads_cate INNER JOIN ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName ORDER BY cateName";
Ultimately, I am trying to get a count of ad_list items in each category.
Is there a MySQL version conflict on what I am trying to do here?
NOTE: I spent some time breaking this down, item by item and the COUNT() seems to cause the array() to disappear. And the the JOIN seemed to do the same thing... It does not help I am developing this on a Yahoo server with no access to the php or mysql error settings.
I think your COUNT syntax is wrong. It should be:
COUNT(ads_cate.id)
or
COUNT(ads_list.id)
depending on what you are counting.
Count is an aggregate. means ever return result set at least one
here you be try count ads_list.id not null but that wrong. how say Myke Count(ads_cate.id) or Count(ads_list.id) is better approach
you have inner join ads_cate.id = ads_list.category so Count(ads_cate.id) or COUNT(ads_list.id) is not necessary just count(*)
now if you dont want null add having
only match
SELECT ads_cate.cateName, COUNT(*),
FROM ads_cate INNER JOIN ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName
having not count(*) is null
ORDER BY cateName
all
SELECT ads_cate.cateName, IFNULL(COUNT(*),0),
FROM ads_cate LEFT JOIN ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName
ORDER BY cateName
Did you try:
$queryCats = "SELECT ads_cate.cateName, COUNT(ads_cate.id)
FROM ads_cate
JOIN ads_list ON ads_cate.id = ads_list.category
GROUP BY ads_cate.cateName";
I am guessing that you need the category to be in the list, in that case the query here should work. Try it without the ORDER BY first.
You were probably getting errors. Check your server logs.
Also, see what happens when you try this:
SELECT COUNT(*), category
FROM ads_list
GROUP BY category
Your array is empty or disappear because your query has errors:
there should be no comma before the FROM
the "ads_list." prefix before COUNT is incorrect
Please try running that query directly in MySQL and you'll see the errors. Or try echoing the output using mysql_error().
Now, some other points related to your query:
there is no need to do ORDER BY because GROUP BY by default sorts on the grouped column
you are doing a count on the wrong column that will always give you 1
Perhaps you are trying to retrieve the count of ads_list per ads_cate? This might be your query then:
SELECT `ads_cate`.`cateName`, COUNT(`ads_list`.`category`) `cnt_ads_list`
FROM `ads_cate`
INNER JOIN `ads_list` ON `ads_cate`.`id` = `ads_list`.`category`
GROUP BY `cateName`;
Hope it helps?