I'm trying to do a search on serialized post meta values in a wordpress database. I know the structure of the serial string so I can search for the preceding value, get the index and then get the number of characters I want before that index value. I cannot effectively use regexp in this particular query because I would like to sort based on the results. This is what I have so far, but I am failing on the syntax and I think it has to do with trying to use the AS keyword and my grouping the AND statements.
SELECT SQL_CALC_FOUND_ROWS _posts.ID FROM _posts
INNER JOIN _postmeta ON (_posts.ID = _postmeta.post_id)
WHERE 1=1
AND _posts.post_type = 'dog'
AND (_posts.post_status = 'publish')
AND ( (_postmeta.meta_key = '_meta_general'
AND CAST(_postmeta.meta_value AS CHAR)) AS dmet
AND POSITION(';s:6:\"weight' IN dmet) AS ddex
AND MID(dmet ,ddex,10)) AS dres
GROUP BY dres ORDER BY dres ASC LIMIT 0, 10
Well, I'm still having issues with the structure of this thing. The previous code did not work, #fenway, after closer inspection. Here is what I have now. The problem with #fenway's answer is that the MID and POSITION values were being called in the select part of the statement that was selecting "FROM" posts. They are located in postmeta. So I attempted to rearrange the string filtering after the INNER JOIN which is joining the postmeta table to the posts table by id. This is not working. I understand that this question is simply due to a lack of my knowledge in SQL, but I'm trying to learn here.
None of these are working as I want. There are syntactical errors. The purpose of the code is to group the returned query by a value that is inside of a serial(json) string. The method is to search for the following value (n this case it would be - ";s:6:"weight -) When I have the index of this string I want to return the preceding 10 values ( a date xx/xx/xxxx ). I want to label this string (AS dres) and have the result sort by dres. Wordpress gathers the posts from the posts table, then gathers the post meta from the postmeta table. The post meta table is where the json is stored. It is really a simple algorithm, it's just the syntax that is screwing with me.
SELECT SQL_CALC_FOUND_ROWS {$wpdb->posts}.ID
FROM {$wpdb->posts} INNER JOIN {$wpdb->postmeta}
MID(CAST({$wpdb->postmeta}.meta_value AS CHAR),
POSITION(';s:6:\"weight' IN CAST({$wpdb->postmeta}.meta_value AS CHAR) ),10 ) AS dres
ON ({$wpdb->posts}.ID = {$wpdb->postmeta}.post_id)
WHERE 1=1
AND {$wpdb->posts}.post_type = 'dog'
AND ({$wpdb->posts}.post_status = 'publish')
AND {$wpdb->postmeta}.meta_key = '_meta_general'
AND POSITION(';s:6:"weight' IN CAST({$wpdb->postmeta}.meta_value AS CHAR)) > 0
GROUP BY {$wpdb->posts}.ID ORDER BY dres ASC LIMIT 0, 10
You can't use column aliases in your WHERE clause -- what's more, in some cases, those expressions with always evaluate to TRUE, so I don't see why there are there at all.
Perhaps you mean:
SELECT SQL_CALC_FOUND_ROWS
_posts.ID
,MID(
CAST(_postmeta.meta_value AS CHAR),
POSITION(';s:6:\"weight' IN CAST(_postmeta.meta_value AS CHAR) ),
10
) AS dres
FROM _posts
INNER JOIN _postmeta ON (_posts.ID = _postmeta.post_id)
WHERE 1=1
AND _posts.post_type = 'dog' AND _posts.post_status = 'publish'
AND _postmeta.meta_key = '_meta_general'
AND POSITION(';s:6:\"weight' IN CAST(_postmeta.meta_value AS CHAR)) > 0
GROUP BY dres ORDER BY _postmeta.meta_value ASC LIMIT 0, 10
Related
I have the following query:
SELECT OBJ_DESC_ERRORS.description, OBJ_DESC_ERRORS.object, OBJ_DESC_ERRORS.count_errors, OBJ_ERRORS.count_total FROM
(SELECT `metrics_event`.`description`, `metrics_event`.`object`, COUNT(`metrics_event`.`id`) AS `count_errors` FROM `metrics_event`
INNER JOIN `metrics_session` ON (`metrics_event`.`session_id` = `metrics_session`.`id`)
WHERE (`metrics_session`.`training_id` = 4 AND NOT (`metrics_session`.`completed_at` IS NULL) )
GROUP BY `metrics_event`.`description`, `metrics_event`.`object` ORDER BY `count_errors` DESC ) as OBJ_DESC_ERRORS
JOIN
(SELECT `metrics_event`.`object`, COUNT(`metrics_event`.`id`) AS `count_total` FROM `metrics_event`
INNER JOIN `metrics_session` ON (`metrics_event`.`session_id` = `metrics_session`.`id`)
WHERE (`metrics_session`.`training_id` = 4 AND NOT (`metrics_session`.`completed_at` IS NULL) )
GROUP BY `metrics_event`.`object` ORDER BY `count_total` DESC ) as OBJ_ERRORS
ON OBJ_DESC_ERRORS.object = OBJ_ERRORS.object
which produces the following result:
As you can see I'm basically running the same query twice. The reason for that is that I need to have that count_errors broken down by each aggregation of object + description, but I also need the count_total to be only aggregated by object. This was the way I could think of. Now I'd like to know if this is the best I can do or if it can be optimized even further.
If so I have no clue how. Googling and searching similar topics on this is difficult because the optimization task depends on the query itself, so keywords here didn't help me much.
Get rid of the inner ORDER BYs; they do nothing useful.
Rewrite the query something like this:
SELECT
me.description,
me.object,
SUM(...) AS count_errors,
SUM(...) AS count_total
FROM `metrics_event` AS me
INNER JOIN `metrics_session` AS ms ON (me.`session_id` = ms.`id`)
WHERE ms.`training_id` = 4
ms.`completed_at` IS NOT NULL
GROUP BY me.`description`, me.`object`
ORDER BY `count_total` DESC
Since a boolean expression evaluates as 1 for TRUE, else 0, devise the argument to SUM() to be a boolean expression that provides the desired COUNT.
I've got a products table that I'm trying to get to work. The query brings back results; however, it isn't actually using the ORDER BY FIELD to sort the results. It's skipping it somehow. I even tried ORDER BY FIELD(sc.id,'4','5','6'), and that didn't work either.
Is it even possible to use table_name.column in an ORDER BY FIELD()? Is there an alternative or a better method of doing this query?
$product = $db1q->query("
SELECT p.id, p.name, p.image, p.url,p.subcat as subcat, sc.id as scid,sc.name as scname
FROM Product as p
JOIN Product_Sub_Category as sc ON p.subcat = sc.id
WHERE p.visibility='1' AND find_in_set(p.id,'". $sidr['products'] ."')
ORDER BY FIELD(p.subcat,'4','5','6'), sc.sort_order ASC, p.sort_order ASC")
or die ('Unable to execute query. '. mysqli_error($db1q));
I just dumbed the query down to the basic level....
$product = $db1q->query("
SELECT id, name, image, url,subcat
FROM Product WHERE visibility='1' AND id IN ({$sidr['products']}) ORDER BY FIELD(subcat,'5','4','6','22')") or die ('Unable to execute query. '. mysqli_error($db1q));
and for some reason the order of my subcats are as follows....
3,12,23,5,5,4,4,4,4,4,22
Why wouldn't they begin with 5, 4, 6(doesn't exist), and 22? Then display 3,12, and 23 after those are first....
Simple Rextester Demo
When datatype is numeric don't compare to 'string' values
eg visibility = '1' if visibility is numeric you really shouldn't have the apostrophes around it. same in the field function given subcat.
$product = $db1q->query("SELECT id, name, image, url,subcat
FROM Product
WHERE visibility='1'
AND id IN ({$sidr['products']})
ORDER BY case when subcat in (5,4,6,22) then 0 else 1 end,
FIELD(subcat,5,4,6,22)
") or die ('Unable to execute query. '. mysqli_error($db1q));
or something like:
order by case when field(sort,'5','4','22') = 0 then (select max(sort)+1+sort from Product)
else field(sort,'5','4','22') end;
The issue with the 2nd approach is that it has to run a subquery for every record. In addition if the size of subcat/sort exceed or approach the max of int we'll run into a problem adding the values together. This problem is negated by using the 2 column sort approach in the first method.
Again, my gut feeling is that the first approach with 2 sort columns would be faster; and in my opinion easier to follow/maintain. The downfall is if the sort order defined changes then we have to change code. So... why have the order defined here... what isn't the order defined in a table; or is the order passed in as a parameter by user?
I have a MySQL query and I need to SUM the content of a column if the content contains the number 1,
This is what I have but the TotalFails returns 0
SELECT
d.SeqNo,
d.SeqText,
h.UniqueID,
h.SeqID,
h.Room,
IF(h.Status = '1', SUM(h.Status), 0) AS TotalFails
FROM ".$SequenceNo_default." d
LEFT
JOIN ".$Hist." h ON h.SeqID = d.SeqID
WHERE d.SeqActive = 1 AND DATE(CompStamp) BETWEEN DATE( '".$_SESSION['StartDate']."') AND DATE('".$_SESSION['EndDate']."')
GROUP BY h.Room
ORDER BY h.Status ASC
Can any one see where I am going wrong?
Please note that Status is a reserved keyword so you may want to change it to something else like myStatus in the statement above.
Edit
Based upon your updated question, I would rewrite your query as follows (again, avoiding the keyword STATUS by replacing Status with myStatus):
SELECT
d.SeqNo,
d.SeqText,
h.UniqueID,
h.SeqID,
h.Room,
SUM(h.myStatus) AS TotalFails
FROM ".$SequenceNo_default." d
LEFT
JOIN ".$Hist." h ON h.SeqID = d.SeqID
WHERE d.SeqActive = 1 AND DATE(CompStamp) BETWEEN DATE( '".$_SESSION['StartDate']."') AND DATE('".$_SESSION['EndDate']."')
GROUP BY h.Room, h.myStatus
ORDER BY h.myStatus ASC
As a separate side note, this should be a prepared query, rather than including the $_SESSION variable directly into the string. $_SESSION is better than $_POST or $_GET, but for maintaining the code, this would be a good habit (for example, what if the code later changes to $_POST?).
Can some one please help me here, ive Googled, and looked at other examples with this error but it just confuses me and i cant seem to get my head around this.
im struggling with selecting data AS something else in a mysql query im getting the following error...
Operand should contain 1 column(s)
What is an simplified term for an Operand?
below is the mysql query...
SELECT atable_garage.id,
atable_garage.total_votes as num_votes,
atable_garage.name,
atable_garage.address,
atable_garage.city,
atable_garage.postcode,
atable_garage.main_dealer,
atable_garage.phone,
atable_garage.website,
atable_garage.description,
atable_garage.years_in_business,
atable_garage.garage_image,
(SELECT(avg(quality_of_repair) + avg(attitude_of_staff) + avg(overall_satisfaction))/3 as rating,
count(*) as num_votes
FROM atable_feedback
WHERE validated = 'Y'
AND atable_garage.id = garage_id)
FROM `atable_garage`
WHERE valeting = 'Y'
AND active = 'Y'
ORDER BY rating DESC, atable_garage.total_votes DESC
Can anyone point out what I've done wrong here? and if possible explain I'm finding it difficult to get my head around this one thanks in advance.
The correlated subquery can only return one column at a time. Since you want to have two column, you can restrusture the query by converting it into LEFT JOIN.
SELECT atable_garage.id,
atable_garage.total_votes as num_votes,
atable_garage.name,
atable_garage.address,
atable_garage.city,
atable_garage.postcode,
atable_garage.main_dealer,
atable_garage.phone,
atable_garage.website,
atable_garage.description,
atable_garage.years_in_business,
atable_garage.garage_image,
COALESCE(b.rating, 0) rating,
COALESCE(b.num_votes, 0) num_votes
FROM atable_garage
LEFT JOIN
(
SELECT garage_id,
(avg(quality_of_repair) + avg(attitude_of_staff) + avg(overall_satisfaction)) / 3.0 as rating,
count(*) as num_votes
FROM atable_feedback
WHERE validated = 'Y'
GROUP BY garage_id
) b ON atable_garage.id = b.garage_id
WHERE valeting = 'Y' AND active = 'Y'
ORDER BY rating DESC,
atable_garage.total_votes DESC
When using a sub-select for a column, you can only return one value, like this:
(SELECT avg(quality_of_repair) + avg(attitude_of_staff) + avg(overall_satisfaction)
FROM atable_feedback
WHERE validated = 'Y'
AND garage_id = atable_garage.id
)/3 as rating,
I'm in over my head with a big mysql query (mysql 5.0), and i'm hoping somebody here can help.
Earlier I asked how to get distinct values from a joined query
mysql count only for distinct values in joined query
The response I got worked (using a subquery with join as)
select *
from media m
inner join
( select uid
from users_tbl
limit 0,30) map
on map.uid = m.uid
inner join users_tbl u
on u.uid = m.uid
unfortunately, my query has grown more unruly, and though I have it running, joining into a derived table is taking too long because there is no indexes available to the derived query.
my query now looks like this
SELECT mdate.bid, mdate.fid, mdate.date, mdate.time, mdate.title, mdate.name,
mdate.address, mdate.rank, mdate.city, mdate.state, mdate.lat, mdate.`long`,
ext.link,
ext.source, ext.pre, meta, mdate.img
FROM ext
RIGHT OUTER JOIN (
SELECT media.bid,
media.date, media.time, media.title, users.name, users.img, users.rank, media.address,
media.city, media.state, media.lat, media.`long`,
GROUP_CONCAT(tags.tagname SEPARATOR ' | ') AS meta
FROM media
JOIN users ON media.bid = users.bid
LEFT JOIN tags ON users.bid=tags.bid
WHERE `long` BETWEEN -122.52224684058 AND -121.79760915942
AND lat BETWEEN 37.07500915942 AND 37.79964684058
AND date = '2009-02-23'
GROUP BY media.bid, media.date
ORDER BY media.date, users.rank DESC
LIMIT 0, 30
) mdate ON (mdate.bid = ext.bid AND mdate.date = ext.date)
phew!
SO, as you can see, if I understand my problem correctly, i have two derivative tables without indexes (and i don't deny that I may have screwed up the Join statements somehow, but I kept messing with different types, is this ended up giving me the result I wanted).
What's the best way to create a query similar to this which will allow me to take advantage of the indexes?
Dare I say, I actually have one more table to add into the mix at a later date.
Currently, my query is taking .8 seconds to complete, but I'm sure if I could take advantage of the indexes, this could be significantly faster.
First, check for indices on ext(bid, date), users(bid) and tags(bid), you should really have them.
It seems, though, that it's LONG and LAT that cause you most problems. You should try keeping your LONG and LAT as a (coordinate POINT), create a SPATIAL INDEX on this column and query like that:
WHERE MBRContains(#MySquare, coordinate)
If you can't change your schema for some reason, you can try creating additional indices that include date as a first field:
CREATE INDEX ix_date_long ON media (date, `long`)
CREATE INDEX ix_date_lat ON media (date, lat)
These indices will be more efficient for you query, as you use exact search on date combined with a ranged search on axes.
Starting fresh:
Question - why are you grouping by both media.bid and media.date? Can a bid have records for more than one date?
Here's a simpler version to try:
SELECT
mdate.bid,
mdate.fid,
mdate.date,
mdate.time,
mdate.title,
mdate.name,
mdate.address,
mdate.rank,
mdate.city,
mdate.state,
mdate.lat,
mdate.`long`,
ext.link,
ext.source,
ext.pre,
meta,
mdate.img,
( SELECT GROUP_CONCAT(tags.tagname SEPARATOR ' | ')
FROM tags
WHERE ext.bid = tags.bid
ORDER BY tags.bid GROUP BY tags.bid
) AS meta
FROM
ext
LEFT JOIN
media ON ext.bid = media.bid AND ext.date = media.date
JOIN
users ON ext.bid = users.bid
WHERE
`long` BETWEEN -122.52224684058 AND -121.79760915942
AND lat BETWEEN 37.07500915942 AND 37.79964684058
AND ext.date = '2009-02-23'
AND users.userid IN
(
SELECT userid FROM users ORDER BY rank DESC LIMIT 30
)
ORDER BY
media.date,
users.rank DESC
LIMIT 0, 30
You might want to compare your perforamnces against using a temp table for each selection, and joining those tables together.
create table #whatever
create table #whatever2
insert into #whatever select...
insert into #whatever2 select...
select from #whatever join #whatever 2
....
drop table #whatever
drop table #whatever2
If your system has enough memory to hold full tables this might work out much faster. It depends on how big your database is.