SQL query to retrieve value or catch all - sql

I'm dealing with a table in the following form:
A B
------ -----------
1 value1
2 value2
3 value3
-1 value4
In this table, the value -1 indicates a catch all, if there's no other match for A in the column. This means, a query for A = 2 should return a single record for which value2 is the value of column B. If the table is queried for, let's say, A = 6, then the value for B should be value4 (because it's the value associated with the catch all).
What's the "best" query to achieve this? Is there a better solution? I've scripted a small setup example in SQLFiddle, if that helps.
The database is SQL Server.
Can you help? Many thanks.

select top (1) A, B
from (
select A, B, 0 as priority from t where A = #value
union
select A, B, 1 from t where A = -1
) foo
order by priority

DECLARE #param int
SET #param = 6
SELECT *
FROM test
WHERE a = #param OR (
a = -1 AND #param NOT IN (SELECT a FROM test)
)
Replace #param = 6 with #param = 2 to test again

Here's how I would write the query:
SELECT TOP 1 B
FROM mytable
WHERE A IN (2,-1)
ORDER BY CASE WHEN A = -1 THEN 1 ELSE 0 END, B;
This statement has a hardcoded search argument of "2" (as in your example).
You would substitute your search argument in place of the hardcoded "2", obviously.
The CASE expression in the ORDER BY clause makes sure that the "catch all" value of -1 is a "last resort", the -1 will be the LAST value in the list, any other any value will come BEFORE the -1 in the sort.
A expr
-- ----
-2 0
-1 1
0 0
1 0
2 0
So, when I ORDER BY expr we are guaranteed that a value of -1 will be LAST in the list. After the resultset is sorted, the TOP 1 will return no more than 1 row. So, the value associated with the -1 "catch all" value will only be returned if no other matching value is found.

In MySQL, this would be trivial:
SELECT b FROM test WHERE a = #var or a = -1 ORDER BY a DESC LIMIT 1;
However, MSSQL doesn't have such a trick built in--you would need to add a stored procedure to limit it properly.
EDIT
It seems that in 2005, they added some paging functions:
SELECT TOP 1 b FROM test WHERE a = #var or a = -1 ORDER BY a DESC;
should work.
All that said, this sounds like an issue of poor design; I would look at the application that needs this and see if there wasn't a cleaner way to achieve a default value.

if exists(select * from YourTable WHERE A=6)
select * from YourTable WHERE A=6
else
select * from YourTable WHERE A<0

Related

SQL QUERY regarding single row as output

I want a query in which it only returns only one output row based on the values in a column.
What I need is
Table A has values
A
----|----
1 |
2 |
3 |
required output
A
----
yes
so I need a query in which if table a has 3 in its column then the output I need to get is yes or else no.
my code:-
WITH
number_tb AS (select * from t1),
out_put as (select case when a = 3 then 'yes' else 'no' end a_case from number_tb)
select * from out_put
output:-
a_case
-----
no
no
yes
I only need single row output. if 3 is present then yes or no, I don't need it for each row.
Is it possible to do so??
If a proper boolean true/false value is also acceptable, you can use
select exists (select * from t1 where a = 3) as a;
If you want a string with yes/no instead you can use a CASE expression to turn the boolean value into a string.
select case
when exists (select * from t1 where a = 3) then 'Yes'
else 'No'
end as a;

Remove parameters from SQL Query in with Regex / LogStash

A 3rd party system I use logs all SQL queries along with rowcount & response time which I then send to Logstash/Elastic to calculate metrics. As this system doesn't use bind variables, and there are 10's of millions of queries a day, I need to be able to rollup the data, which I can't do if the majority of queries are unique. I need a way to replace the SQL query parameters with '?' as Oracle would do via Cursor Sharing.
i.e.
replace
'SELECT * FROM table_name WHERE id = 123'
with
'SELECT * FROM table_name WHERE id = ?'
I have access to Ruby scripting magic in Logstash, but unfortunately all of the google results for 'sql regex' or similar return results of how to use regular expressions in SQL, not the other way round. Before I go crafting a regular expression parser, I thought I would check in here to see if others have tried to solve a similar problem.
FYI, have looked at implementing a solution using a Ruby SQL AST library such as https://github.com/lfittl/pg_query but plugging Ruby libraries in to Logstash becomes more of a problem of writing a custom Filter plugin to do the work, which may be the answer, but i'm hoping I'm missing something obvious.
I am not a logstash/ruby developer/user, but in terms of regular expression you may try this one:
(=\s\W\w+\W|=\s\d+)
You can test this here
SELECT * FROM Table1 WHERE Column1 = 1
SELECT * FROM Table1 WHERE Column1 = 'abc'
SELECT * FROM Table1 WHERE (Column1 = 'abc' OR Column2 = 1)
SELECT * FROM Table1 WHERE (Column1 = 'abc' AND Column2 = 1) OR Column2 = 'zxy'
SELECT * FROM Table1 WHERE (Column1 = 'abc' AND Column2 = 1) OR Column2 = 'zxy' AND
Column3 = 2
SELECT * FROM Table1 WHERE Column1 = 1 AND Column2 = 2
Expected Results:
Match 1
Full match = 1
Group 1. = 1
Match 2
Full match = 'abc'
Group 1. = 'abc'
Match 3
Full match = 'abc'
Group 1. = 'abc'
Match 4
Full match = 1
Group 1. = 1
Match 5
Full match = 'abc'
Group 1. = 'abc'
Match 6
Full match = 1
Group 1. = 1
Match 7
Full match = 'zxy'
Group 1. = 'zxy'
Match 8
Full match = 'abc'
Group 1. = 'abc'
Match 9
Full match = 1
Group 1. = 1
Match 10
Full match = 'zxy'
Group 1. = 'zxy'
Match 11
Full match = 2
Group 1. = 2
Match 12
Full match = 1
Group 1. = 1
Match 13
Full match = 2
Group 1. = 2
Based on these results you can create a function to replace the value of '= 2' to '= ?'.
Hope that it at least gives you a starting point.

single query that defines 2 tables has same row

query 1
(select count(*) from CALENDAR)
it returns 15
query 2
(select value from PARAMETER where name = 'PLAN_HORIZON')
it returns 15 too only when my programs runs without error. if error occurs,
it returns 10 or other values.
this↓ is wrong sql, but i want a single query which returns True or False.
select if (query1 == query2)
How can I define 2 sql has same result in a query?
The following SQL statement returns 0 or 1. It runs with SQL Server
SELECT CASE WHEN (select count(*) from CALENDAR) = (select value from PARAMETER where name = 'PLAN_HORIZON') THEN 1 ELSE 0 END
Something like this:
select count(*) = 0
from (
select count(*)
from calendar
except
select value
from parameter
where name = 'PLAN_HORIZON'
) t
You didn't specify your DBMS, but the above is standard SQL.
Try this query !
SELECT
CASE
WHEN (select count(*) from CALENDAR) = (select value from PARAMETER
where name = 'PLAN_HORIZON')
THEN true
ELSE false
END ;

SELECT <A OR B> FROM my_table WHERE A=5 OR B=5;

SELECT <A OR B> FROM my_table WHERE A=5 OR B=5;
Say the values (A,B) are:
1,5
2,5
5,3
5,4
The result of SELECT should be
1
2
3
4
In other words I need the value from the other column (other than the one found by WHERE).
You could try this:
SELECT
CASE WHEN a = 5 THEN b
ELSE a
END AS AorB
FROM my_table
WHERE a = 5 OR b = 5
In case there's no CASE in your SQL dialect, another possible solution comes to my mind, which, however, does not retain the order of the rows.
SELECT b AS AorB FROM my_table WHERE a = 5
UNION ALL
SELECT a AS AorB FROM my_table WHERE b = 5
Please note that this query explicitly allows for duplicate values in the result set! If you want to see distinct values, you should omit the ALL.
Assuming both A and B are numeric values, I wonder which solution will work faster, using CASE, UNION (both are general solutions) or a query like this one:
SELECT (A + B - 5) AS OtherValue
FROM Table
WHERE A = 5
OR B = 5;
Assuming your database supports case expressions, and assuming both A and B are of the same data type - this should work:
SELECT CASE WHEN A = 5 THEN B ELSE A END AS OtherValue
FROM Table
WHERE A = 5
OR B = 5;
If you are looking for a very readable query then use UNION:
select a from my_table where b = 5
union
select b from my_table where a = 5;
I think this will work:
SELECT CASE WHEN a = 5 THEN b ELSE a END val FROM #tmpAll WHERE 5 IN (a, b)

SQL, Select if or select case

I am not sure what I am trying is achievable or not!!
I am trying to write a SQL query will will do select statement based on user input.
so if user input = 1 then I want it to select from actual table.
if user input = 0 then I want it do select 0 or null from dual. (if this is possible).
so Here is Parameter which will used to get input from user. ?i_userkey:'':null?
if user input's 1 then it will change null to 1.
I want to write a query using this parameter. something like this.
below is the logic.
IF i_userkey = 1 then
select ID,Gender,Age from TableA
If i_userkey = 0 then
select 0 or null from dual.
is this possible?
How about this:
SELECT
CASE WHEN i_userkey = 1 THEN ID ELSE NULL END AS ID
CASE WHEN i_userkey = 1 THEN Gender ELSE NULL END AS Gender
CASE WHEN i_userkey = 1 THEN AGE ELSE NULL END AS Age
FROM TableA
This will at least give you a consistent three-column result set you can work with. Having the query return differing column counts is not going to work.
select ID,Gender,Age
from TableA
where i_userkey = 1
union all
select 0, 0, 0
from dual
where i_userkey = 0
You might have to adjust the datatypes in the dual-select to match TableA