wordpress custom mysql query - mysql

In wordpress How can we fetch records in specific order within meta field value for eg I need to fetch all records where zip_code(meta key name) is all fields with 60007 first than all 60143 than 60191
Table drrr_posts
Id | post_name | content
2
3
4
22
32
43
Table drrr_postmeta
id | meta_key | meta_value | post_id
1 | zip_code | 60143 | 2
2 | zip_code | 60007 | 3
3 | zip_code | 60191 | 4
4 | zip_code | 60143 | 22
5 | zip_code | 60007 | 32
6 | zip_code | 60143 | 43
I think issue is I am passing ORDER BY FIELD( drrr_postmeta.meta_value not zip_code which is meta_key
In mysql I can easily pass the values in ORDERBY like
ORDER BY FIELD(name, 'B', 'A', 'D', 'E', 'C')
here is what I have now
My Query is
SELECT SQL_CALC_FOUND_ROWS drrr_posts.ID
FROM drrr_posts
INNER JOIN drrr_term_relationships ON ( drrr_posts.ID = drrr_term_relationships.object_id )
INNER JOIN drrr_postmeta ON ( drrr_posts.ID = drrr_postmeta.post_id )
INNER JOIN drrr_postmeta AS mt1 ON ( drrr_posts.ID = mt1.post_id )
WHERE 1 =1
AND drrr_posts.ID NOT
IN ( 91, 89, 87, 66 )
AND (
drrr_term_relationships.term_taxonomy_id
IN ( 11 )
)
AND drrr_posts.post_type = 'doctors'
AND (
(
drrr_posts.post_status = 'publish'
)
)
AND (
drrr_postmeta.meta_key = 'zip_code'
AND (
mt1.meta_key = 'zip_code'
AND CAST( mt1.meta_value AS SIGNED )
IN (
'60007', '60143', '60191', '60005', '60106', '60157', '60173', '60008', '60056', '60172'
)
)
)
GROUP BY drrr_posts.ID
ORDER BY FIELD( drrr_postmeta.meta_value, '60007', '60143', '60191', '60005', '60106', '60157', '60173', '60008', '60056', '60172' )
LIMIT 0 , 8

You can order your results by meta_key by adding one more conditional order by ,also your group by statement doesn't make any sense in absence of aggregate function ,for now you can do this
ORDER BY
drrr_postmeta.meta_key ='zip_code' desc,
FIELD( drrr_postmeta.meta_value, '60007', '60143', '60191', '60005', '60106', '60157', '60173', '60008', '60056', '60172' )
Using drrr_postmeta.meta_key ='zip_code' will result as a boolean and returns true if both matches so it will order results first by zip_code matching meta_key and then you field() function will order results accordingly

Related

MySQL Max with wrong fields

When executing below query
SELECT `game_turns`.`in_darts`, `game_turns`.`date`, MAX(game_turns.score) AS max_score
FROM `game_turns`
JOIN `games` ON `games`.`id` = `game_turns`.`game_id` AND `games`.`training` = 1
WHERE `game_turns`.`uid` = 2
AND `game_turns`.`out` = 1
AND `game_turns`.`in_darts` = 3
ORDER BY `game_turns`.`score` DESC
LIMIT 1
I get the max score for that user id (uid) and out in 3 darts, but the rest (date) is wrong.
Fields are
Score Uid GameID Score out in_darts date
121 2 4 8 1 3 2015-07-21 13:52:12
8465 2 142 100 1 3 2015-09-05 19:46:29
It returns the score 100 from row ID 8465 but the rest is from row ID 121
I have googled it and came on some Stackoverflow results saying that I should use ORDER BY and LIMIT 1, but looks like it aint working for me.
Order by Date also didn't do the trick.
A simple order by and limit should do what you want:
SELECT gt.`in_darts`, gt.`date`, gt.score
FROM `game_turns` gt JOIN
`games` g
ON g.`id` = gt.`game_id` AND g.`training` = 1
WHERE gt.`uid` = 2 AND gt.`out` = 1 AND gt.`in_darts` = 3
ORDER BY gt.`score` DESC
LIMIT 1;
There is no need for aggregation.
If seeking a solution that would work for multiple UID's then aggregation becomes useful - via a subquery.
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`Score_A` int, `Uid` int, `GameID` int, `Score_B` int, `out` int, `in_darts` int, `date` datetime)
;
INSERT INTO Table1
(`Score_A`, `Uid`, `GameID`, `Score_B`, `out`, `in_darts`, `date`)
VALUES
(121, 2, 4, 8, 1, 3, '2015-07-21 13:52:12'),
(8465, 2, 142, 100, 1, 3, '2015-09-05 19:46:29')
;
Query 1:
SELECT
t.*
FROM table1 t
INNER JOIN (
SELECT Uid, max(Score_B) as Score_B
FROM table1
GROUP BY uid
) msb ON t.Uid = msb.Uid and t.Score_B = msb.Score_B
Results:
| Score_A | Uid | GameID | Score_B | out | in_darts | date |
|---------|-----|--------|---------|-----|----------|-----------------------------|
| 8465 | 2 | 142 | 100 | 1 | 3 | September, 05 2015 19:46:29 |

combining rows in same table sql

sample_data
id_type,seq_no,acct_name,_acct#,address
12345,67,jiimm,,167 s.40th st
12345,67,jiimm joe the 3rd,,167 s.40th st
12345,67,jiimm
12345,67,,0981_1,po box 1234
12345,80,Lee,,1234 street ave
12345,80,Lee
12345,80,,588_1,109 road st
CODE
SELECT `ID`_type,
seq_no,
MAX(`acct_name`) AS acct_name,
MAX(`acct_#`) AS acct_#,
address
FROM `test_table`
GROUP BY `ID`_type,
seq_no;
I want to merge rows based on by id_type and seq_no. I am using max to merge the rows but I am overwriting any exisiting addresses and acct_names due to the MAX acct#.
my results
id_type,seq_no.,acct_name,_acct#,address
12345,67,jiimm joe the 3rd,0981_1,167 s.40th st
12345,80,Lee,588_1,109 road st
Losing po box 1234 for 67-
Losing 1234 street ave for 80, losing jiimm-
desired results
12345,80,Lee,588_1,109 road st
12345,80,Lee,588_1,1234 street ave
12345,67,jiimm,0981_1,167 s.40th st
12345,67,jiimm,0981_1,po box 1234
12345,67,jiimm joe the 3rd,0981_1,167 s.40th st
This gives you what you're looking for, but read my comment / question underneath your question above. There is an ambiguous "pick one row from many" situation that needs clarification. In that ambiguous situation, you imply that rules call for delivering the minimum non-blank account name, which this code does, but you can see how it requires treating the account name one way, and treating the acct (#) and address a different way. I think you're headed for an application that delivers results based on hard to remember rules. Funky rules like that end up getting reported as defects, even if you publish said processing rules. Hence, you may want to enhance the process upstream that captures this data to deliver more disciplined data.
SQLFIDDLE link - In short the inner query populates missing values, then the outer result set delivers the distinct rows. I tested this with blank values not null. I did make a quick effort to add the code to handle nulls, but I didn't test it using nulls, so I suggest testing it as such if that is what production will use.
select distinct * from (
select d.id_type, d.seq_no
,coalesce( nullif( acct_name, ''), min_acct_name ) as merged_acct_name
,coalesce( nullif( acct, ''), max_acct ) as merged_acct
,coalesce( nullif( address, ''), max_address ) as merged_address
from test_table d
left join ( select id_type, seq_no
,max( acct ) as max_acct
,max( address ) as max_address
from test_table
group by id_type, seq_no
) as max_
on max_.id_type = d.id_type and max_.seq_no = d.seq_no
and ( coalesce( d.acct,'' ) = ''
or coalesce( d.address,'' ) = '' )
left join ( select id_type, seq_no
,min( acct_name ) as min_acct_name
from test_table
where coalesce( acct_name, '' ) <> ''
group by id_type, seq_no
) as min_
on min_.id_type = d.id_type and min_.seq_no = d.seq_no
and coalesce( d.acct_name,'' ) = ''
) as t
order by id_type, seq_no desc, merged_acct_name, merged_acct, merged_address
Try this:
select distinct t1.id_type, t1.seq_no
,coalesce( t1.acct_name, t2.acct_name ) as merged_acct_name
,coalesce( t1.acct, t2.acct ) as merged_acct
,coalesce( t1.address, t2.address ) as merged_address
from test_table t1
left join test_table t2
on t1.id_type = t2.id_type
and t1.seq_no = t2.seq_no
where concat(coalesce( t1.acct_name, t2.acct_name )
,coalesce( t1.acct, t2.acct )
,coalesce( t1.address, t2.address ) ) is not null
order by t1.id_type, t1.seq_no;
Or:
select distinct t1.id_type, t1.seq_no
,coalesce( t1.acct_name, t2.acct_name ) as merged_acct_name
,coalesce( t1.acct, t3.acct ) as merged_acct
,coalesce( t1.address, t4.address ) as merged_address
from test_table t1
left join test_table t2
on t1.id_type = t2.id_type
and t1.seq_no = t2.seq_no
left join test_table t3
on t1.id_type = t3.id_type
and t1.seq_no = t3.seq_no
left join test_table t4
on t1.id_type = t4.id_type
and t1.seq_no = t4.seq_no
where concat(coalesce( t1.acct_name, t2.acct_name )
,coalesce( t1.acct, t3.acct )
,coalesce( t1.address, t4.address ) ) is not null
order by t1.id_type, t1.seq_no;
SQL Fiddle Demo
SELECT
D1.id_type
, D1.seq_no
, IFNULL(D1.acct_name, (SELECT MIN(acct_name) FROM data D WHERE D.id_type = D1.id_type AND D.seq_no = D1.seq_no)) t
, IFNULL(D1.acct_no, (SELECT MAX(acct_no) FROM data D WHERE D.id_type = D1.id_type AND D.seq_no = D1.seq_no)) s
, D1.address
FROM data D1
WHERE D1.address IS NOT NULL
ORDER BY id_type, seq_no DESC, acct_name
;
returns
| ID_TYPE | SEQ_NO | T | S | ADDRESS |
|---------|--------|-------------------|--------|-----------------|
| 12345 | 80 | Lee | 588_1 | 109 road st |
| 12345 | 80 | Lee | 588_1 | 1234 street ave |
| 12345 | 67 | jiimm | 0981_1 | po box 1234 |
| 12345 | 67 | jiimm | 0981_1 | 167 s.40th st |
| 12345 | 67 | jiimm joe the 3rd | 0981_1 | 167 s.40th st |
Which is consistent with your expected output except for the order of the third and fourth row. However, for larger amounts of data MAX and MIN will become more and more likely to be of limited help.
SQL Fiddle

Mysql ORDER BY or GROUP BY for newsfeed

I want to create something like Facebook newsfeed: a person who follows other persons see their last posts at the top. I use this query as db select query but it has some problem.
Does anyone have any idea to improve this query?
These are important tables for this query:
______
| wall |
-------------------------------------------------------------------------------------
postID | inserterID | sportID | catID | title|insertDate|context|abstraction|editeDate
-------------------------------------------------------------------------------------
|follower|
---------------------
ID | foerID | foingID
---------------------
SELECT wall.postID
, wall.inserterID
, wall.title
, wall.insertDate
, wall.editDate
, wall.context
, user.lastName
, cat.catName
, wall.catID
, pic.picname AS pic
, foerID
FROM wall
JOIN user
ON user.userID = wall.inserterID
JOIN postcategory cat
ON cat.catID = wall.catID
LEFT
JOIN wallpic pic
ON pic.postID = wall.postID
LEFT
JOIN follow
ON follow.foingID = wall.inserterID
WHERE wall.inserterID != 71
GROUP
BY wall.postID
ORDER
BY follow.foerID IN (71) DESC
, wall.insertDate DESC
LIMIT 0,100

Query returns ids specified in NOT IN case

The following query still returns the value 10643 even though it's specifically listed in the NOT IN condition.
SELECT
`media` . `id`
FROM
`media`
LEFT JOIN
`categories` ON `categories`.`id` = `media`.`category_id`
JOIN
`users` ON `users`.`id` = `media`.`author`
WHERE
`media`.`public` =1
AND
`media`.`date_posted` <= (SELECT CONVERT_TZ(now(),'US/Pacific','US/Eastern'))
AND
`media`.`date_posted` > DATE_SUB((SELECT CONVERT_TZ(now(),'US/Pacific','US/Eastern')) , INTERVAL 25 DAY )
AND
`media`.`id` NOT IN ('10659,10656,10655,10654,10653,10652,10651,10650,10649,10648,10646,10647,10645,10644,10643')
ORDER BY
`media`.`views` DESC
LIMIT 15
Tables
Categories
id | category
Media
id | type | category_id | title | subtitle | author | image | content | public | date_posted | views
Users
id | firstname | lastname
Your syntax for NOT IN () is incorrect. You were giving it a single string, do it like this instead:
SELECT
`media` . `id`
FROM
`media`
LEFT JOIN
`categories` ON `categories`.`id` = `media`.`category_id`
JOIN
`users` ON `users`.`id` = `media`.`author`
WHERE
`media`.`public` =1
AND
`media`.`date_posted` <= (SELECT CONVERT_TZ(now(),'US/Pacific','US/Eastern'))
AND
`media`.`date_posted` > DATE_SUB((SELECT CONVERT_TZ(now(),'US/Pacific','US/Eastern')) , INTERVAL 25 DAY )
AND
`media`.`id` NOT IN ('10659', '10656' , '10655', '10654', '10653', '10652', '10651', '10650', '10649', '10648', '10646', '10647', '10645', '10644', '10643')
ORDER BY
`media`.`views` DESC
LIMIT 15
You have quotations around the numbers
Try NOT IN (10659, 10660 ...)

How to use multiple IN - Where IN (...) and IN (...)

I'm tuning performance of my script and I changed the way posts categories are sorted.
I was using successfully the following query.
It selects posts with (130|3|4|5) categories and checks if it also has (73) category init as one post can have multiple categories.
SELECT *
FROM post
LEFT JOIN post_plus
ON ( post.id = post_plus.news_id )
WHERE category REGEXP '[[:<:]](130|3|4|5)[[:>:]]'
AND category REGEXP '[[:<:]](73)[[:>:]]'
AND approve = 1
ORDER BY fixed DESC,
date DESC
LIMIT 0, 7
Now with a new query I need to perform multiple IN (...) queries instead of AND category REGEXP '...', but for some reason additional AND categoryid IN always returns empty result.
SELECT *
FROM post
LEFT JOIN post_plus
ON ( post.id = post_plus.news_id )
LEFT JOIN post_category
ON ( post_category.postid = post.id )
WHERE categoryid IN ( 130, 3, 4, 5 )
AND categoryid IN ( 73 )
AND approve = 1
ORDER BY fixed DESC,
date DESC
LIMIT 0, 7;
post_category structure
+-----+--------+------------+
| cid | postId | categoryId |
+-----+--------+------------+
| 824 | 7 | 10 |
| 825 | 7 | 13 |
| 826 | 7 | 16 |
| 827 | 7 | 29 |
| 828 | 7 | 71 |
+-----+--------+------------+
To get the postid for posts that are both in category 73 and in at least one of category id 130, 3, 4, 5 you can use
SELECT postid
FROM post_category
GROUP BY postid
HAVING MAX(CASE
WHEN categoryid = 73 THEN 1
END) = 1
AND MAX(CASE
WHEN categoryid IN ( 130, 3, 4, 5 ) THEN 1
END) = 1
This can be used in a derived table to join onto your wider query.
Or another possibility is
SELECT c1.postid
FROM post_category c1
JOIN post_category c2
ON c1.postid = c2.postid
WHERE c1.categoryid IN ( 130, 3, 4, 5 )
AND c2.categoryid = 73
You can use an INTERSECT-compound statement:
SELECT postid
FROM post_category
WHERE categoryid = 73
INTERSECT
SELECT postid
FROM post_category
WHERE categoryid IN (130, 3, 4, 5)
This will select only those postids that have a categoryid equal to 73 and at least one of categoryid = 130, 3, 4, or 5.
This query will probably run faster than a aggregate-query (GROUP BY), since the sql-server can use the index on categoryid (which you hopefully have) to get the relevent postids and then uses a temporary index to compute the intersection (at least thats what sqlite does). If there there are no postids with categoryid 73, then the second part of the query is never executed, since the intersection of an empty set with anything else is always just the empty set.
To get your posts, use a subquery:
SELECT post.*
FROM post
WHERE post.id IN (SELECT postid
FROM post_category
WHERE categoryid = 73
INTERSECT
SELECT postid
FROM post_category
WHERE categoryid IN (130, 3, 4, 5))
Also note that you can add more INTERSECT-compounds as you like.