ORA-00936: missing expression using prompt - sql

Cannot get a CASE WHEN to work in my query using a variable.
select field1, field2
from table
where 1=1
AND GLCC.SEGMENT2
(CASE
WHEN :P_AccountType = 'B' THEN < 40000
WHEN :P_AccountType = 'P' THEN => 40000
ELSE
BETWEEN '00000' AND '99999'
END)
any idea where/what I do wrong
Many thanks.

I don't think the variable is the problem, you can't build a WHERE clause with syntax like that, as far as I can see.
Also, what is the 1=1 for?
And the => should surely be the other way round.
And why are you using a numeric representation of the number in two places and a character one in the other?
Try
select field1, field2 from table
where (GLCC.SEGMENT2 < 40000 and :P_AccountType = 'B')
or (GLCC.SEGMENT2 >= 40000 and :P_AccountType = 'P' )
or (GLCC.SEGMENT2 BETWEEN 0 AND 99999 and :P_AccountType not in ('B','P'))
or something like that (not in a position to test!)

I think you need such a collation as below :
SELECT field1, field2
FROM "table"
WHERE
(CASE
WHEN :P_AccountType = 'B' AND SEGMENT2 < '40000' THEN 1
WHEN :P_AccountType = 'P' AND SEGMENT2 >= '40000' THEN 1
ELSE
CASE WHEN SEGMENT2 BETWEEN '00000' AND '99999' THEN 1 END
--> the above case line is needed when :P_AccountType is neither "B", nor "P"
END) = 1

Related

How can I use CASE clause twice in SQL Query

I am trying to apply two conditions in one SQL Query.
(select DISTINCT (
CASE WHEN (
ABC.GemUserID = '99' )
OR ABC.GemUserID != '99'
THEN 'Yes'
ELSE 'No'
END)) AS AllWell
This gives me output as "Yes" where as the CASE is true only for 1 file like below :
Current Result:
99 , Yes
99 , Yes
99 , Yes
Expected Result:
99 , No
99 , No
99 , Yes
I am using the below query but the SQL Query Intellisence is identifying it as wrong.
Wrong Query:
(select DISTINCT (
CASE WHEN ( ABC.GEMUserID = '99' THEN 'Yes' else 'No'
CASE WHEN ( ABC.GEMUserID != '99' THEN 'No' else 'Yes'
END)) AS AllWell
After fixing the above Wrong Query:
(select DISTINCT
(CASE WHEN ABC.GemUserID = '99' THEN 'Yes' else 'No' END),
(CASE WHEN ABC.GemUserID != '99' THEN 'No' else 'Yes' END))
AS AllWell
But I am getting error:
Msg 116, Level 16, State 1, Line 17 Only one expression can be
specified in the select list when the subquery is not introduced with
EXISTS.
How to fix this?
select distinct is -- itself -- part of SQL syntax. The distinct is not a function. It should not be followed by parentheses. So, if I understand your question:
select DISTINCT
( CASE WHEN ABC.GEMUserID = '99' THEN 'Yes' else 'No' END),
( CASE WHEN ABC.GEMUserID <> '99' THEN 'No' else 'Yes' END) as AllWell
Do you plan on giving the first column a name?
select DISTINCT
CASE WHEN ABC.GEMUserID = '99' THEN 'Yes'
ELSE 'No' -- This is automatically When ABC.GEMUserID <> '99'
END AS AllWell
According to the error, your query is a subquery (probably behind IN?) in a larger SQL command. Therefore, it is not possible for such subquery to return more than one column.
So your first query, you've said:
CASE WHEN userID = 99 OR userID != 99
In other words:
CASE WHEN 1=1
This is why it returns yes for everything (not sure what the difference between your current and expected result should be considering that the userID is 99 for all rows).
For your erroneous query, seems you're returning that select in the middle of another select (since you alias it at the end). Due to that, you cannot return more than one column in your nested select. You do not need the second CASE statement, simply change your query to:
(select DISTINCT
CASE WHEN ABC.GemUserID = '99' THEN 'Yes' Else 'No' End) AS AllWell
Assuming that you hold the missing pieces to the query such as the FROM.

ORACLE: USE RESULT OF CASE-WHEN-STATEMENT

I have a huge query and I am wondering if it is in Oracle possible
to get the result of a case-when-statement and use it for comparison? My CASE-STATEMENT is declared in the Select-Statement and it looks like this.
SELECT........
(CASE
WHEN (Select 1 from DUAL) = 1 THEN 'TEST'
ELSE 'TEST2'
END) AS TEST;
Now I want to get the result of this case-statement and use it in the where part? Is it possible? (Sry this may be a dumb question)
If you define your CASE statement in either an inline-view or a common table expression (aka WITH clause), you can refer to it by whatever alias you give it.
For example (inline-view):
SELECT ...
FROM ( SELECT .....
(CASE
WHEN (Select 1 from DUAL) = 1 THEN 'TEST'
ELSE 'TEST2'
END) AS TEST
FROM...
) v
WHERE v.test = 'TEST2';
As a common table expression, it would be:
WITH cte AS ( SELECT........
(CASE
WHEN (Select 1 from DUAL) = 1 THEN 'TEST'
ELSE 'TEST2'
END) AS TEST
FROM ... )
SELECT ...
FROM cte
WHERE test = 'TEST2';
You can use a case statement in the where clause, for eg.:
select * from table
where table.field = (CASE
WHEN (Select 1 from DUAL) = 1 THEN 'TEST'
ELSE 'TEST2'
END)
This will compare the value returned from the case statement with the table field.

ORACLE: SELECT VALUE IF

I am trying to select different values that depend on different conditions, but I don't exactly know, how one can achieve this in SQL/Oracle..
Here is an example:
SELECT VALUE (I dont exactly know what to write here)
FROM
(SELECT
(CASE
WHEN (Select 1 from DUAL) = 1 THEN 'TEST'
WHEN (Select 1 from DUAL) = 0 THEN 'TEST1'
WHEN (Select 1 from DUAL) = 0 THEN 'TEST2'
ELSE 'N/A'
END)
FROM DUAL);
I want to print different results according to the conditions...For instance, in the example above it should print "TEST"
You need to provide an alias to the CASE statement:
SELECT alias_for_your_case_value
FROM (
SELECT CASE (Select 1 from DUAL)
WHEN 1 THEN 'TEST'
WHEN 0 THEN 'TEST1'
WHEN 0 THEN 'TEST2'
ELSE 'N/A'
END AS alias_for_your_case_value
FROM DUAL
);

Case Statement embedded in NVL

I am trying to setup the below logic in as a divisor. I need to use NVL() to avoid the divide by zero error. I need to get a distinct count of the case statement.
Here is what I have:
(NVL(COUNT(DISTINCT
CASE WHEN ({field1} = 'a' OR {field1} = 'b' OR
{field1} = 'c' OR {field1} = 'd') AND
({field2} = 'a' OR {field2} = 'b') AND
({field3} > TO_DATE('01-JAN-2017', 'DD-MON-YYYY'))
THEN 1 END), 1))
There is something wrong with my syntax but cannot figure it out.
Any help would be appreciated. Thank you!
I changed lots of ORs to simpler IN
COUNT(DISTINCT
CASE
WHEN field1 IN ('a','b','c','d')
AND field2 IN ('a','b')
AND field3 > TO_DATE('01-JAN-2017', 'DD-MON-YYYY')
THEN 1
END)
COUNT(DISTINCT ...) doesn't return null, so removed redundant NVL
Now, the above will result is either 0 or 1.
You probably want this without distinct:
COUNT(
CASE
WHEN field1 IN ('a','b','c','d')
AND field2 IN ('a','b')
AND field3 > TO_DATE('01-JAN-2017', 'DD-MON-YYYY')
THEN 1
END)
Since, it is a divisor, it can't be 0, so you'll have to place safeguard for that. One sensible output in case the divisor is 0 is null. One way to achieve that is:
case when (expression) <> 0 then dividend/(expression) end

How do I perform an IF...THEN in an SQL SELECT?

How do I perform an IF...THEN in an SQL SELECT statement?
For example:
SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product
The CASE statement is the closest to IF in SQL and is supported on all versions of SQL Server.
SELECT CAST(
CASE
WHEN Obsolete = 'N' or InStock = 'Y'
THEN 1
ELSE 0
END AS bit) as Saleable, *
FROM Product
You only need to use the CAST operator if you want the result as a Boolean value. If you are happy with an int, this works:
SELECT CASE
WHEN Obsolete = 'N' or InStock = 'Y'
THEN 1
ELSE 0
END as Saleable, *
FROM Product
CASE statements can be embedded in other CASE statements and even included in aggregates.
SQL Server Denali (SQL Server 2012) adds the IIF statement which is also available in access (pointed out by Martin Smith):
SELECT IIF(Obsolete = 'N' or InStock = 'Y', 1, 0) as Saleable, * FROM Product
The case statement is your friend in this situation, and takes one of two forms:
The simple case:
SELECT CASE <variable> WHEN <value> THEN <returnvalue>
WHEN <othervalue> THEN <returnthis>
ELSE <returndefaultcase>
END AS <newcolumnname>
FROM <table>
The extended case:
SELECT CASE WHEN <test> THEN <returnvalue>
WHEN <othertest> THEN <returnthis>
ELSE <returndefaultcase>
END AS <newcolumnname>
FROM <table>
You can even put case statements in an order by clause for really fancy ordering.
From SQL Server 2012 you can use the IIF function for this.
SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM Product
This is effectively just a shorthand (albeit not standard SQL) way of writing CASE.
I prefer the conciseness when compared with the expanded CASE version.
Both IIF() and CASE resolve as expressions within a SQL statement and can only be used in well-defined places.
The CASE expression cannot be used to control the flow of execution of
Transact-SQL statements, statement blocks, user-defined functions, and
stored procedures.
If your needs can not be satisfied by these limitations (for example, a need to return differently shaped result sets dependent on some condition) then SQL Server does also have a procedural IF keyword.
IF #IncludeExtendedInformation = 1
BEGIN
SELECT A,B,C,X,Y,Z
FROM T
END
ELSE
BEGIN
SELECT A,B,C
FROM T
END
Care must sometimes be taken to avoid parameter sniffing issues with this approach however.
You can find some nice examples in The Power of SQL CASE Statements, and I think the statement that you can use will be something like this (from 4guysfromrolla):
SELECT
FirstName, LastName,
Salary, DOB,
CASE Gender
WHEN 'M' THEN 'Male'
WHEN 'F' THEN 'Female'
END
FROM Employees
Use CASE. Something like this.
SELECT Salable =
CASE Obsolete
WHEN 'N' THEN 1
ELSE 0
END
SELECT
(CASE
WHEN (Obsolete = 'N' OR InStock = 'Y') THEN 'YES'
ELSE 'NO'
END) as Salable
, *
FROM Product
Microsoft SQL Server (T-SQL)
In a select, use:
select case when Obsolete = 'N' or InStock = 'Y' then 'YES' else 'NO' end
In a where clause, use:
where 1 = case when Obsolete = 'N' or InStock = 'Y' then 1 else 0 end
From this link, we can understand IF THEN ELSE in T-SQL:
IF EXISTS(SELECT *
FROM Northwind.dbo.Customers
WHERE CustomerId = 'ALFKI')
PRINT 'Need to update Customer Record ALFKI'
ELSE
PRINT 'Need to add Customer Record ALFKI'
IF EXISTS(SELECT *
FROM Northwind.dbo.Customers
WHERE CustomerId = 'LARSE')
PRINT 'Need to update Customer Record LARSE'
ELSE
PRINT 'Need to add Customer Record LARSE'
Isn't this good enough for T-SQL?
SELECT
CASE
WHEN OBSOLETE = 'N' or InStock = 'Y' THEN 'TRUE'
ELSE 'FALSE'
END AS Salable,
*
FROM PRODUCT
Simple if-else statement in SQL Server:
DECLARE #val INT;
SET #val = 15;
IF #val < 25
PRINT 'Hi Ravi Anand';
ELSE
PRINT 'By Ravi Anand.';
GO
Nested If...else statement in SQL Server -
DECLARE #val INT;
SET #val = 15;
IF #val < 25
PRINT 'Hi Ravi Anand.';
ELSE
BEGIN
IF #val < 50
PRINT 'what''s up?';
ELSE
PRINT 'Bye Ravi Anand.';
END;
GO
Use a CASE statement:
SELECT CASE
WHEN (Obsolete = 'N' OR InStock = 'Y')
THEN 'Y'
ELSE 'N'
END as Available
etc...
A new feature, IIF (that we can simply use), was added in SQL Server 2012:
SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
Use pure bit logic:
DECLARE #Product TABLE (
id INT PRIMARY KEY IDENTITY NOT NULL
,Obsolote CHAR(1)
,Instock CHAR(1)
)
INSERT INTO #Product ([Obsolote], [Instock])
VALUES ('N', 'N'), ('N', 'Y'), ('Y', 'Y'), ('Y', 'N')
;
WITH cte
AS
(
SELECT
'CheckIfInstock' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Instock], 'Y'), 1), 'N'), 0) AS BIT)
,'CheckIfObsolote' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Obsolote], 'N'), 0), 'Y'), 1) AS BIT)
,*
FROM
#Product AS p
)
SELECT
'Salable' = c.[CheckIfInstock] & ~c.[CheckIfObsolote]
,*
FROM
[cte] c
See working demo: if then without case in SQL Server.
For start, you need to work out the value of true and false for selected conditions. Here comes two NULLIF:
for true: ISNULL(NULLIF(p.[Instock], 'Y'), 1)
for false: ISNULL(NULLIF(p.[Instock], 'N'), 0)
combined together gives 1 or 0. Next use bitwise operators.
It's the most WYSIWYG method.
SELECT 1 AS Saleable, *
FROM #Product
WHERE ( Obsolete = 'N' OR InStock = 'Y' )
UNION
SELECT 0 AS Saleable, *
FROM #Product
WHERE NOT ( Obsolete = 'N' OR InStock = 'Y' )
SELECT CASE WHEN profile.nrefillno = 0 THEN 'N' ELSE 'R'END as newref
From profile
case statement some what similar to if in SQL server
SELECT CASE
WHEN Obsolete = 'N' or InStock = 'Y'
THEN 1
ELSE 0
END as Saleable, *
FROM Product
This isn't an answer, just an example of a CASE statement in use where I work. It has a nested CASE statement. Now you know why my eyes are crossed.
CASE orweb2.dbo.Inventory.RegulatingAgencyName
WHEN 'Region 1'
THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
WHEN 'Region 2'
THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
WHEN 'Region 3'
THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
WHEN 'DEPT OF AGRICULTURE'
THEN orweb2.dbo.CountyStateAgContactInfo.ContactAg
ELSE (
CASE orweb2.dbo.CountyStateAgContactInfo.IsContract
WHEN 1
THEN orweb2.dbo.CountyStateAgContactInfo.ContactCounty
ELSE orweb2.dbo.CountyStateAgContactInfo.ContactState
END
)
END AS [County Contact Name]
If you're inserting results into a table for the first time, rather than transferring results from one table to another, this works in Oracle 11.2g:
INSERT INTO customers (last_name, first_name, city)
SELECT 'Doe', 'John', 'Chicago' FROM dual
WHERE NOT EXISTS
(SELECT '1' from customers
where last_name = 'Doe'
and first_name = 'John'
and city = 'Chicago');
As an alternative solution to the CASE statement, a table-driven approach can be used:
DECLARE #Product TABLE (ID INT, Obsolete VARCHAR(10), InStock VARCHAR(10))
INSERT INTO #Product VALUES
(1,'N','Y'),
(2,'A','B'),
(3,'N','B'),
(4,'A','Y')
SELECT P.* , ISNULL(Stmt.Saleable,0) Saleable
FROM
#Product P
LEFT JOIN
( VALUES
( 'N', 'Y', 1 )
) Stmt (Obsolete, InStock, Saleable)
ON P.InStock = Stmt.InStock OR P.Obsolete = Stmt.Obsolete
Result:
ID Obsolete InStock Saleable
----------- ---------- ---------- -----------
1 N Y 1
2 A B 0
3 N B 1
4 A Y 1
SELECT CASE WHEN Obsolete = 'N' or InStock = 'Y' THEN 1 ELSE 0
END AS Saleable, *
FROM Product
You can have two choices for this to actually implement:
Using IIF, which got introduced from SQL Server 2012:
SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
Using Select Case:
SELECT CASE
WHEN Obsolete = 'N' or InStock = 'Y'
THEN 1
ELSE 0
END as Saleable, *
FROM Product
Using SQL CASE is just like normal If / Else statements.
In the below query, if obsolete value = 'N' or if InStock value = 'Y' then the output will be 1. Otherwise the output will be 0.
Then we put that 0 or 1 value under the Salable Column.
SELECT
CASE
WHEN obsolete = 'N' OR InStock = 'Y'
THEN 1
ELSE 0
END AS Salable
, *
FROM PRODUCT
Question:
SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product
ANSI:
Select
case when p.Obsolete = 'N'
or p.InStock = 'Y' then 1 else 0 end as Saleable,
p.*
FROM
Product p;
Using aliases -- p in this case -- will help prevent issues.
SELECT
if((obsolete = 'N' OR instock = 'Y'), 1, 0) AS saleable, *
FROM
product;
For those who uses SQL Server 2012, IIF is a feature that has been added and works as an alternative to Case statements.
SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM Product
It will be something like that:
SELECT OrderID, Quantity,
CASE
WHEN Quantity > 30 THEN "The quantity is greater than 30"
WHEN Quantity = 30 THEN "The quantity is 30"
ELSE "The quantity is under 30"
END AS QuantityText
FROM OrderDetails;
I like the use of the CASE statements, but the question asked for an IF statement in the SQL Select. What I've used in the past has been:
SELECT
if(GENDER = "M","Male","Female") as Gender
FROM ...
It's like the Excel or sheets IF statements where there is a conditional followed by the true condition and then the false condition:
if(condition, true, false)
Furthermore, you can nest the if statements (but then use should use a CASE :-)
(Note: this works in MySQL Workbench, but it may not work on other platforms)
For the sake of completeness, I would add that SQL uses three-valued logic. The expression:
obsolete = 'N' OR instock = 'Y'
Could produce three distinct results:
| obsolete | instock | saleable |
|----------|---------|----------|
| Y | Y | true |
| Y | N | false |
| Y | null | null |
| N | Y | true |
| N | N | true |
| N | null | true |
| null | Y | true |
| null | N | null |
| null | null | null |
So for example if a product is obsolete but you dont know if product is instock then you dont know if product is saleable. You can write this three-valued logic as follows:
SELECT CASE
WHEN obsolete = 'N' OR instock = 'Y' THEN 'true'
WHEN NOT (obsolete = 'N' OR instock = 'Y') THEN 'false'
ELSE NULL
END AS saleable
Once you figure out how it works, you can convert three results to two results by deciding the behavior of null. E.g. this would treat null as not saleable:
SELECT CASE
WHEN obsolete = 'N' OR instock = 'Y' THEN 'true'
ELSE 'false' -- either false or null
END AS saleable
There are multiple conditions.
SELECT
(CASE
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1001' THEN 'DM'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1002' THEN 'GS'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1003' THEN 'MB'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1004' THEN 'MP'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1005' THEN 'PL'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1008' THEN 'DM-27'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1011' THEN 'PB'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1012' THEN 'UT-2'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1013' THEN 'JGC'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1014' THEN 'SB'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1015' THEN 'IR'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1016' THEN 'UT-3'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1017' THEN 'UT-4'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1019' THEN 'KR'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1020' THEN 'SYB-SB'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1021' THEN 'GR'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1022' THEN 'SYB-KP'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1026' THEN 'BNS'
ELSE ''
END) AS OUTLET
FROM matrixcrm.Transact