Oracle SQL sort by ternary operation - sql

I'm trying to sort records in ORACLE SQL such that all strings that contain the phrase 'VENT' are sorted to the top, and the others are sorted by length.
Select D1.MENU_TEXT
from IMPRESSIONS_DEF D1
order by IFF(instr(D1.MENU_TEXT, 'VENT'),1, LENGTH(D1.MENU_TEXT));
I tried this, but it fails with "IFF" invalid identifier. I also tried
Select D1.MENU_TEXT, iff(D1.MENU_TEXT like '%VENT%', 1, 200) as k
from IMPRESSIONS_DEF D1
order by k + Length(D1.Menu_Text);
and it says "missing right parenthesis"

Use a case expression:
ORDER BY (CASE WHEN MENU_TEXT LIKE '%VENT%' THEN 1 ELSE 2 END),
LENGTH(D1.MENU_TEXT);
CASE is standard SQL. IIF() is bespoke SQL only used by a few databases.

Related

why 'select (0 < 1)' does not work in Sql Server?

If I let MySQL execute SELECT (0 < 1), it return 1; But if I run this select statement with SQL Server, it give me an error:
Incorrect syntax near '<'.
I also have tested other operator like != and <, and get the same error. I'm confused. '0 < 1' is an expression, why can't SQL Server evaluate it?
This behavior is by design:
Unlike other SQL Server data types, a Boolean data type cannot be
specified as the data type of a table column or variable, and cannot
be returned in a result set.
[...]
Expressions with Boolean data types are used in the WHERE clause to
filter the rows that qualify for the search conditions and in
control-of-flow language statements such as IF and WHILE
So Boolean datatype exists, you just cannot use it outside WHERE clause (etc).
The correct SQL Server equivalent of MySQL SELECT x < 1 (which returns 0, 1 or NULL) would be:
SELECT CASE
WHEN x < 1 THEN 1
WHEN NOT (x < 1) THEN 0
ELSE NULL -- you can omit this line
END
Finally, LEN(NULL) is NULL and (generally speaking) any operation on NULL yields NULL. So the condition IF LEN(NULL) < 1 will not execute, neither will IF LEN(NULL) >= 1.
MS SQL doesn't have a boolean type. It supports boolean expressions, but those cannot be values in variables or result sets.
The best you can do is something like
select case when 0 < 1 then 0 else 1 end
The result set will have a normal integer (the bit type is sometimes used to represent true/false values, but it's just a number with possible values of 1 and 0).
I'm confused. '0 < 1' is an expression, why can't SQL Server evaluate it?
It sort of is and sort of isn't. It's a predicate, and SQL Server treats predicates differently from other expressions which produce values.
SQL Server doesn't have a user-visible boolean data type so you cannot write an expression that produces a value of this non-existent data type.
You can only use predicates in specific positions, such as the WHERE clause, ON clauses, WHEN clauses (part of a CASE expression) and CHECK constraints (there are others)

Hive - SELECT inside WHEN clause of CASE function gives an error

I am trying to write a query in Hive with a Case statement in which the condition depends on one of the values in the current row (whether or not it is equal to its predecessor). I want to evaluate it on the fly, this way, therefore requiring a nested query, not by making it another column first and comparing 2 columns. (I was able to do the latter, but that's really second-best). Does anyone know how to make this work?
Thanks.
My query:
SELECT * ,
CASE
WHEN
(SELECT lag(field_with_duplicates,1) over (order by field_with_duplicates) FROM my_table b
WHERE b.id=a.id) = a.field_with_duplicates
THEN “Duplicate”
ELSE “”
END as Duplicate_Indicator
FROM my_table a
Error:
java.sql.SQLException: org.apache.spark.sql.AnalysisException: cannot recognize input near 'SELECT' 'lag' '(' in expression specification; line 4 pos 9
Notes:
The reason I needed the complicated 'lag' function is that the unique Id's in the table are not consecutive, but I don't think that's where it's at: I tested by substituting another simpler inner query and got the same error message.
Speaking of 'duplicates', I did search on this issue before posting, but the only SELECT's inside CASE's I found were in the THEN statement, and if that works the same, it suggests mine should work too.
You do not need the subquery inside CASE:
SELECT a.* ,
CASE
WHEN prev_field_with_duplicates = field_with_duplicates
THEN “Duplicate”
ELSE “”
END as Duplicate_Indicator
FROM (select a.*,
lag(field_with_duplicates,1) over (order by field_with_duplicates) as prev_field_with_duplicates
from my_table a
)a
or even you can use lag() inside CASE instead without subquery at all (I'm not sure if it will work in all Hive versions ):
CASE
WHEN lag(field_with_duplicates,1) over (order by field_with_duplicates) = field_with_duplicates
THEN “Duplicate”
ELSE “”
END as Duplicate_Indicator
Thanks to #MatBailie for the answer in his comment. Don't I feel silly...
Resolved

SQL : Coalesce within where clause giving error Oracle (Not in DB2)

I am trying to use COALESCE in WHERE clause, and I am getting the following error:
ORA-00907: missing right parenthesis Failed SQL stmt:
If I remove the COALESCE, I don't get the error anymore. I am not sure why would it give me this error as the parenthesis seem correct. Here's my SQL statement:
SELECT S.OPRID, A.OPRNAME, S.EMAIL_ADDR
FROM TABLE1 S, TABLE2 A
WHERE COALESCE(S.REHIRE_DT,S.ORIG_HIRE_DT)
BETWEEN (TO_DATE(TO_CHAR(SYSDATE,'YYYY-MM- DD'),'YYYY-MM-DD') - 3 DAY)
AND (TO_DATE(TO_CHAR(SYSDATE,'YYYY-MM-DD'),'YYYY-MM-DD') - 1 DAY)
AND S.EMPLSTATUS = 'A'
AND A.EMPLID = S.EMPLID
ORDER BY S.OPRID
Take the "DAY" word out. That is not used in oracle in that manner:
SELECT S.OPRID, A.OPRNAME, S.EMAIL_ADDR
FROM TABLE1 S, TABLE2 A
WHERE COALESCE(S.REHIRE_DT,S.ORIG_HIRE_DT)
BETWEEN (TO_DATE(TO_CHAR(SYSDATE,'YYYY-MM- DD'),'YYYY-MM-DD') - 3 )
AND (TO_DATE(TO_CHAR(SYSDATE,'YYYY-MM-DD'),'YYYY-MM-DD') - 1 )
AND S.EMPLSTATUS = 'A'
AND A.EMPLID = S.EMPLID
ORDER BY S.OPRID
"DAY" is a keyword to be used as part of the EXTRACT function - see Here
The default unit of subtraction from a date field is already in units of days. I am not familiar with DB2, but I am assuming that your usage of DAY is a DB2-specific attribute. That is probably not portable SQL. Yes, oracle's error messages can be confusing at times.
Now that I think about it, you can replace all that "TO_DATE" stuff with just:
BETWEEN TRUNC(SYSDATE)-3 AND TRUNC(SYSDATE)-1

order by sql data using condtions (case) based on derived columns

I want to put a condtion to sort SQL data based on the value of derived columns as follows:
SELECT DISTINCT sp.ID
, sp.Status
, sp.Rank
, sp.Price
, sp.SalePrice
, sp.Width
, sp.Height
, sp.QOH
, (sp.SalePrice*sp.QOH) As 'sp.Value'
, (sp.Price*sp.QOH) As 'sp.StandardValue'
FROM table
WHERE -- Conditions
ORDER BY
CASE WHEN 'sp.SalePrice' > 0 THEN 'sp.Value' END DESC,
CASE WHEN 'sp.SalePrice' = 0 THEN 'sp.StandardValue' END DESC
Gves this error:
Msg 145, Level 15, State 1, Line 1
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
if i try
ORDER BY
CASE WHEN sp.SalePrice > 0 THEN (sp.SalePrice*sp.QOH) As "sp.Value" END DESC,
CASE WHEN sp.SalePrice = 0 THEN (sp.Price*sp.QOH) As sp.StandardValue" END DESC
Gives error:
Incorrect syntax near the keyword 'As'.
it starts giving the same select distinct error if i try to remove aliases * as from order by cluase & only leave the multiplication part
I'm going to add a bunch of suggestions about general conventions below, but as to the main problem consider what you're trying to do with this example:
My_Table:
id value
1 1
2 2
3 1
Now, try to show distinct value ordering by id. Which should it be?
value
1
2
or
value
2
1
So, you're asking SQL Server to do something that may be impossible or at least unclear.
Now, as to conventions... Maybe some of this is just how you've posted here, but I would make the following suggestions for your code:
Avoid using reserved and SQL language words for names. This would include table, rank, and status.
Avoid using special characters in names. This would include sp.value. Sure, you can do it with a quoted identifier, but some front-ends, etc. might not support them even if SQL does and you don't really buy anything by using them in most cases.
Use the quoted identifier when you have to quote names. If you absolutely must violate one of the above two suggestions, use the standard quoted identifiers for SQL Server, which are [ and ]. If you want to quote aliases, use these as well (and you shouldn't have to typically quote aliases BTW). This helps to avoid the problem that Mark B points out.
Your CASE statement can be better written as one ordering column. Also, you should include an ELSE in most cases to avoid unhandled conditions. This may not be needed here as long as you can't have NULLs or negative values in any of the involved columns.
CASE
WHEN sp.SalePrice > 0 THEN (sp.SalePrice*sp.QOH)
WHEN sp.SalePrice = 0 THEN (sp.Price*sp.QOH)
END
I would personally avoid using the table alias (which it looks like you accidentally left out of your query) as part of your column aliases. It makes it much more confusing IMO because it makes it look like that aliased column is actually a column in the table.
Your second example is closest as it specifies the columns correctly. However, you cannot alias columns in the order by. This would work:
ORDER BY
CASE WHEN sp.SalePrice > 0 THEN sp.SalePrice*sp.QOH END DESC,
CASE WHEN sp.SalePrice = 0 THEN sp.Price*sp.QOH END DESC
Or alternatively just use the alias you defined in the result set:
ORDER BY
CASE WHEN sp.SalePrice > 0 THEN [sp.Value] END DESC,
CASE WHEN sp.SalePrice = 0 THEN [sp.StandardValue] END DESC
Note the brackets [].... this is required to define the column name as you used a dotted name in the alias... otherwise sp.Value would be considered to be the Value column in the sp table.
using ' around field names turns them into strings. Either remove the quotes entirely, or use " instead.

DB2 count(*) over(partition by fieldname) giving -104 z/OS version 7

I have slimmed down the query to remove potential complications, in addition I have verified that the fields are correct. DB2 UDB zSeries V7 is my db2 version.
SELECT
STDINSTRCD,
COUNT(*) OVER(PARTITION BY STDINSTRCD),
CAST(STDINSTRDESC AS VARCHAR(1000)) AS INSTR,
C.STDINSTRSEQ,
1
FROM
SYST.SCC004 C
WHERE
C.STDINSTRCD = '098'
I have tried a subquery as well.
select
H2.FRSTSTDINSTRCD,
(select count(*) from SYST.scC004 Ci where '098'=Ci.STDINSTRCD) as cnt,
cast(STDINSTRDESC as varchar(1000)),
C.STDINSTRSEQ,
1
from SYST.scE4A00 H2
LEFT OUTER JOIN SYST.scC004 C
ON C.STDINSTRCD = H2.FRSTSTDINSTRCD
WHERE
H2.CTLENTYID='MCS'
AND H2.VCKVAL='12654'
AND H2.POKVAL='0198617S12 000 000'
The error is receive is om.ibm.db2.jcc.b.SqlException: DB2 SQL error: SQLCODE: -104, SQLSTATE: 42601, SQLERRMC: (;, FROM INTO sqlcode sqlstate
-104 Illegal Symbol token.
42601 A character, token, or clause is invalid or missing.
Any advice? I have been unable to determine what syntax error I might me making.
are there any weird special characters in there that might not be printing?
http://www-01.ibm.com/support/docview.wss?uid=swg1IY43009
basically sounds like a weird cr/lf or special char? Any copy pasting from *nix to windows ?
Also, I'm not sure why you need partition by anyway? would a group by not accomplish your goal. (looks like your just counting number of rows that met your criteria)...
something like this for your first query?
SELECT
STDINSTRCD,
count(1) ,
CAST(STDINSTRDESC AS VARCHAR(1000)) AS INSTR,
C.STDINSTRSEQ,
1
FROM SYST.SCC004 C
WHERE C.STDINSTRCD = '098'
group by
STDINSTRCD,
CAST(STDINSTRDESC AS VARCHAR(1000)) AS INSTR,
C.STDINSTRSEQ,
1
Db2 Version 7 for z/OS does not support OLAP functions, or row_number(). You need to rewrite your query to avoid using such functions. They arrived in later Db2 versions. See also other people's tips on alternatives via this link.