SQL query with CASE WHEN used in WP_query wordpress function - sql

I have this SQL query: SELECT * FROM `wpgo_postmeta` WHERE `meta_key` = 'price' ORDER BY CASE WHEN meta_value REGEXP '^[0-9]+$' THEN 1 ELSE 0 END, meta*value+0 DESC; *that works for me but I need to convert it so it's used by the wordpress apply_filters function.
I have tried multiple things including this WordPress Query: ORDER BY CASE WHEN
But then it returns an empty list. I know the query works because I have tested it manually.
I also tried this and it looks like it should work, but I get an empty list as well.
$query_args['meta_key'] = 'fave_property_price';
$query_args['orderby'] = "CASE WHEN meta_value REGEXP '^[0-9]+$' THEN 1 ELSE 0 END, metavalue+0 DESC;";

It looks like you want your numeric meta_value results to appear after the non-numeric ones.
In SQL you can simplify your ORDER BY like this.
ORDER BY (meta_value REGEXP '^[0-9]+$'), meta_value DESC
It works because the output of Boolean comparison operations appear a 1 for true and 0 for false.The parentheses aren't strictly necessary but they make the code a bit easier to read.
But, you cannot just stuff this SQL style clause into a WP_Query() object. Replacing the ORDER BY clause is tricky.
Start by converting this into a WP_Query operation. Those things don't look a whole lot like pure SQL. You need something like this, not debugged.
$q = new WP_Query (
['meta_key' => 'price',
'order' => 'DESC',
'orderby' => 'meta_value_num',
]);
Then you'll get your posts in numeric order by price, with oddball results for non-numeric prices. Run this query and convince yourself you get the posts you want, even if not in the perfect order.
Only then, put a filter handler on the posts_orderby filter to put in your SQLish custom ordering clause. The post you referenced shows how to do that: WordPress Query: ORDER BY CASE WHEN
Use John Blackbourn's Query Monitor plugin to see what your query looks like in real life, after all the WP_Query code finishes assembling it. The correct use of query filters can sometimes be confusing.
If code is poetry then the WP_Query code is an occult spell invocation chant. Sigh.

Related

How to combine LIKE and CASE WHEN in SQLite?

...Hi, a database ingenue here. I'm trying to figure out how to use LIKE with CASE in SQLite, or some equivalent approach. I've got a prod_names table that contains concatenated data--occasionally just 1 item, but usually containing several comma-separated items. For my new 'Toy' column, I need to find every record that contains 'CapGun'. The code below works only when 'CapGun' is the only item, and not when there are multiple items (eg, 'BarbieDoll, CapGun, EasyBakeOven').
SELECT
customer_id,
prod_names,
CASE prod_names WHEN 'CapGun' THEN 'CG' ELSE 'not_CG' END Toy
FROM
Toys_table
ORDER BY
Toy
I've tried various approaches like WHEN LIKE '%CapGun%', WHEN INSTR(prod_names,'CapGun') > 0, and WHEN GLOB '*CapGun*' but they all return no results or throw a syntax error.
Any suggestions? I'm sure there must be a simple solution.
Use the expanded case syntax:
CASE
WHEN prod_names LIKE '%CapGun%' THEN ...
ELSE ...
END
This lets use any expression as the condition in your CASE, including other columns.

How to sort an SQL query by the number of OR results

I am using VBA and SQLdeveloper to compare multiple keyword inputs against a database. I either search using all ANDs or all ORs, the ANDs has been working fine, but I want the OR's to return based on the number of successful comparisons. The code I have currently seems to return the results in a random fashion, rather than how I want it which is essentially relevancy. Here's an example of my code:
Dim sSQLOrder As String
sSQLOrder = " ORDER BY ( Title LIKE '%Title Keyword 1%' + Title LIKE '%Title
Keyword 2%' + ...) DESC"
From my understanding, this should sort it, but doesn't. I've also tried sorting ASC vs DESC, which changes the order, but not in any productive way. Thanks for reading this.
In any database, you should be able to use the ANSI standard CASE expression:
ORDER BY (CASE WHEN Title LIKE '%Title Keyword 1%' THEN 1 ELSE 0 END +
CASE WHEN Title LIKE '%Title Keyword 1%' THEN 1 ELSE 0 END +
. . .
) DESC
Try running the SQL in Oracle SQL Developer first, then later define the string in VBA and execute as a PASS THROUGH query (ADODB connection).
If you're trying to use CASE WHEN in the Jet engine, it will fail. Native Access only allows "immediate if" IIF() functions--which you can still throw into the ORDER BY clause (it will just be messy since it's not as powerful as CASE WHEN).

Pentaho Dynamic SQL queries

I have a Pentaho CDE project in development and i wanted to display a chart wich depends on several parameters (like month, year, precise date, country, etc). But when i want to "add" another parameter to my query, it doesn't work anymore... So i'm sure i'm doing something wrong but what ? Please take a look for the parameter month for example :
Select_months_query : (this is for my checkbox)
SELECT
"All" AS MONTH(TransactionDate)
UNION
SELECT DISTINCT MONTH(TransactionDate) FROM order ORDER BY MONTH(TransactionDate);
Select_barchart_query : (this is for my chart, don't mind the other tables)
SELECT pginit.Family, SUM(order.AmountEUR) AS SALES
FROM pginit INNER JOIN statg ON pginit.PG = statg.PGInit INNER JOIN order ON statg.StatGroup = order.StatGroup
WHERE (MONTH(order.TransactionDate) IN (${month}) OR "All" IN (${month}) OR ${month} IS NULL) AND
/*/* Apply the same pattern for another parameter (like year for example) *\*\
GROUP BY pginit.Family
ORDER BY SALES;
(Here, ${month} is a parameter in CDE)
Any ideas on how to do it ?
I read something there that said to use CASE clauses... But how ?
http://forums.pentaho.com/showthread.php?136969-Parametrized-SQL-clause-in-CDE&highlight=dynamic
Thank you for your help !
Try simplifying that query until it runs and returns something and work from there.
Here are some things I would look into as possible causes:
I think you need single quotes around ${parameter} expressions if they're strings;
"All" should probably be 'All' (single quotes instead of double quotes);
Avoid multi-line comments. I don't think you can have multi-line comments in CDE SQL queries, although -- for single line comments usually works.
Be careful with multi-valued parameters; they are passed as arrays, which CDA will convert into comma separated lists. Try with a single valued parameter, using = instead of IN.

SQL produced by Entity Framework for string matching

Given this linq query against an EF data context:
var customers = data.Customers.Where(c => c.EmailDomain.StartsWith(term))
You’d expect it to produce SQL like this, right?
SELECT {cols} FROM Customers WHERE EmailDomain LIKE #term+’%’
Well, actually, it does something like this:
SELECT {cols} FROM Customer WHERE ((CAST(CHARINDEX(#term, EmailDomain) AS int)) = 1)
Do you know why?
Also, replacing the Where selector to:
c => c.EmailDomain.Substring(0, term.Length) == term
it runs 10 times faster but still produces some pretty yucky SQL.
NOTE: Linq to SQL correctly translates StartsWith into Like {term}%, and nHibernate has a dedicated LikeExpression.
I don't know about MS SQL server but on SQL server compact LIKE 'foo%' is thousands time faster than CHARINDEX, if you have INDEX on seach column. And now I'm sitting and pulling my hair out how to force it use LIKE.
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/1b835b94-7259-4284-a2a6-3d5ebda76e4b
The reason is that CharIndex is a lot faster and cleaner for SQL to perform than LIKE. The reason is, that you can have some crazy "LIKE" clauses. Example:
SELECT * FROM Customer WHERE EmailDomain LIKE 'abc%de%sss%'
But, the "CHARINDEX" function (which is basically "IndexOf") ONLY handles finding the first instance of a set of characters... no wildcards are allowed.
So, there's your answer :)
EDIT: I just wanted to add that I encourage people to use CHARINDEX in their SQL queries for things that they didn't need "LIKE" for. It is important to note though that in SQL Server 2000... a "Text" field can use the LIKE method, but not CHARINDEX.
Performance seems to be about equal between LIKE and CHARINDEX, so that should not be the reason. See here or here for some discussion. Also the CAST is very weird because CHARINDEX returns an int.
charindex returns the location of the first term within the second term.
sql starts with 1 as the first location (0 = not found)
http://msdn.microsoft.com/en-us/library/ms186323.aspx
i don't know why it uses that syntax but that's how it works
I agree that it is no faster, I was retrieving tens of thousands of rows from our database with the letter i the name. I did find however that you need to use > rather than = ... so use
{cols} FROM Customer WHERE ((CAST(CHARINDEX(#term, EmailDomain) AS int)) > 0)
rather than
{cols} FROM Customer WHERE ((CAST(CHARINDEX(#term, EmailDomain) AS int)) = 1)
Here are my two tests ....
select * from members where surname like '%i%' --12 seconds
select * from sc4_persons where ((CAST(CHARINDEX('i', surname) AS int)) > 0) --12 seconds
select * from sc4_persons where ((CAST(CHARINDEX('i', surname) AS int)) = 1) --too few results

SQL Query - Use Like only if no exact match exists?

I'm having an issue with a query that currently uses
LEFT JOIN weblog_data AS pwd
ON (pwd.field_id_41 != ''
AND pwd.field_id_41 LIKE CONCAT('%', ewd.field_id_32, '%'))
However I'm discovering that I need it to only use that if there is no exact match first. What's happening is that the query is double dipping due to the use of LIKE, so if it tests for an exact match first then it will avoid the double dipping issue. Can anyone provide me with any further guidance?
It sounds like you want to join the tables aliased as pwd and ewd in your snippet based first on an exact match, and if that fails, then on the like comparison you have now.
Try this:
LEFT JOIN weblog_data AS pwd1 ON (pwd.field_id_41 != '' AND pwd.field_id_41 = ewd.field_id_32)
LEFT JOIN weblog_data AS pwd2 ON (pwd.field_id_41 != '' AND pwd.field_id_41 LIKE CONCAT('%', ewd.field_id_32, '%'))
Then, in your select clause, use something like this:
select
isnull(pwd1.field, pwd2.field)
however, if you are dealing with a field that can be null in pwd, that will cause problems, this should work though:
select
case pwd1.nonnullfield is null then pwd2.field else pwd1.field end
You'll also have to make sure to do a group by, as the join to pwd2 will still add rows to your result set, even if you end up ignoring the data in it.
you're talking about short circuit evaluation.
Take a look at this article it might help you:
http://beingmarkcohen.com/?p=62
using TSQL, run an exact match, check for num of rows == 0, if so, run the like, otherwise don't run the like or add the like results below the exact matches.
I can only think of doing it in code. Look for an exact match, if the result is empty, look for a LIKE.
One other option is a WHERE within this query such that WHERE ({count from exact match}=0), in which case, it wont go through the comparison with LIKE if the exact match returns more than 0 results. But its terribly inefficient... not to mention the fact that using it meaningfully in code is rather difficult.
i'd go for a If(count from exact match = 0) then do like query, else just use the result from exact match.