SQL Server switch data to display something else - sql

I am trying to figure out I can change the data on the fly.
This is my current query:
SELECT [EmployeeTC_No] AS "Employee TC#"
,[pye_nlast] AS "Name Last"
,[pye_nfirst] AS "Name First"
,[Dept] AS "Department"
,[pye_status] AS "Active"
,[HireDate] AS "Hire Date"
,[SeparationDate] AS "Separation Date"
FROM [testing].[dbo].[testing]
In the column of pye_status the data comes in as "A" or "T" and I want it to be "1" or "0".
I have tried to add a case statement trying to do some kind of switch but nothing appears to even get me close.

CASE/WHEN should do the trick:
,CASE WHEN [pye_status] = 'A' THEN 1
WHEN [pye_status] = 'T' THEN 0
ELSE NULL END AS "Active"
Or a simple case/when will work too:
, CASE [pye_status]
WHEN 'A' THEN 1
WHEN 'T' THEN 0
ELSE NULL END AS "Active"

Use CASE expression or IIF() function as
CASE WHEN [pye_status] = 'A' THEN 1 ELSE 0 END AS [Active]
OR
IIF([pye_status] = 'A', 1, 0) AS [Active]

Related

SQL command not properly ended in Python OracleSQL

I'm having some trouble with SQL code that works when I run it in DBeaver, but when I execute it with cx_Oracle it comes up with the error of:
cx_Oracle.DatabaseError: ORA-00933: SQL command not properly ended
The python code is good, but I'm not much of a SQL programmer, so maybe someone can look to see if there is any obvious coding errors. It's just weird that the code works in DBeaver but not with cx_Oracle.
Here is the code:
WITH MDVC_LP_HEADER_DATA AS
(select
distinct trunc(lh.start_time) as "Consumption Date",
md.client_co_account_id as "NMI",
md.MR_MDVC_NUMBER as "Meter",
lh.mdvc_id,
lh.header_id,
lh.lp_attribute_id,
lh.entry_date,
lh.rec_status,
cm.register_id as "Register",
nvl(st.crm_register_id, st.register_id) as "Register_ID",
st.stream_id as "Stream"
from WACSMDMS.mdvc_lp_header lh,
WACSMDMS.metering_device md,
WACSMDMS.lp_attribute_config c,
WACSMDMS.ozwave_register_channel_map cm,
WACSMDMS.nem12_subs_members st
where 1=1
and md.mdvc_id = lh.mdvc_id
and lh.entry_date between to_date('26-JUL-2021') + 1 and to_date('2-AUG-2021')+1
and lh.rec_status in ('VFD', 'VDD')
and lh.lp_attribute_id = c.lp_attribute_id
and cm.channel_id = c.channel_id
and st.nmi = md.client_co_account_id
and st.meter_number = md.MR_MDVC_NUMBER
and st.register_id = cm.register_id
and st.stream_id != 'X'
and st.subscriber_acr = 'EVERGY'
),
mdvc_lp_dta as
(
select
distinct
lh."Consumption Date" as "Consumption Date",
lh."NMI" as "NMI",
lh."Meter" as "Meter",
lh.mdvc_id as "MDVC_ID",
lh.lp_attribute_id,
lh.rec_status,
lp.comments as "Reason Description",
lp.DATA_ID, lp.STATUS, lp.reason_code, lh."Register", lh."Stream" , lh."Register_ID"
from WACSMDMS.mdvc_lp_data lp, WACSMDMS.MDVC_LP_HEADER_DATA lh
where 1=1
and lh.mdvc_id = lp.mdvc_id
and lh.lp_attribute_id = lp.lp_attribute_id
and lh.header_id = lp.header_id
and lp.end_time > lh.entry_date -1
and lp.end_time <= lh.entry_date
),
base as
(select
lp."Consumption Date",
lp."NMI",
lp."Meter",
lp."MDVC_ID",
lp."Reason Description",
lp.DATA_ID,
lp.STATUS,
lp.reason_code,
NVL(a.GUI_DISPLAY_DESC,a.description) subs_type,
CASE
WHEN orcd.reason_code IS NOT NULL THEN orcd.reason_code||' ('||orcd.reason_description|| ')'
ELSE NULL
END AS "Reason Code",
CASE
WHEN lp.DATA_ID = 1 AND lp.STATUS IS NOT NULL THEN 'Substituted'
ELSE
CASE WHEN lp.DATA_ID = 0 THEN 'Actual'
ELSE NVL(LDS.GUI_DISPLAY_DESC,LDS.DESCRIPTION)
END
END AS read_data_id,
NVL(a.GUI_DISPLAY_DESC,a.description) AS read_data_status,
lp.rec_status as rec_status2,
lds.dataid_status_ind,
a.dataid_status_ind dataid_status_ind2, lp."Register", lp."Stream", lp."Register_ID"
from
WACSMDMS.mdvc_lp_dta lp,
WACSMDMS.lp_data_status a,
WACSMDMS.lp_data_status lds,
WACSMDMS.ozwave_reason_code_dim orcd
where 1=1
and a.mr_gateway_id IS NULL
AND a.dataid_status_ind(+) = 'S'
AND a.file_data_status_id(+) = lp.status
AND lp.data_id = lds.file_data_status_id (+)
AND lds.mr_gateway_id (+) IS NULL
AND lds.dataid_status_ind (+) = 'D'
and lp.reason_code =orcd.reason_code (+)
)
select "Consumption Date","NMI","Meter","Register","MDVC_ID",
( case when subs_type is null and read_data_id = 'Churn Substitution' and
read_data_status is null then 'Type 19 Zero' else subs_type end ) as "Substitution Type",
"Reason Code","Reason Description",read_data_id as "Data Quality", "Stream", "Register_ID"
from base
where 1=1
and ( ( base.read_data_id = 'Churn Substitution' and base.read_data_status is null ) or
( base.rec_status2 = 'VDD' and base.subs_type is not null and base.read_data_id <> 'Final Substitution' ))
order by 1,2,3,4;
Query itself looks OK (as you said, it works in DBeaver). Maybe it is that Python doesn't "like" closing statement terminator (semi-colon at the very end of the query) - try to remove it.
Apart from that, I'd suggest you not to rely on Oracle's guessing date format. Instead of TO_DATE ('26-JUL-2021'), use TO_DATE ('26-JUL-2021', 'DD-MON-YYYY') (i.e. always provide appropriate format mask). Note that MON can be tricky if database doesn't speak English (for example, it would fail in my database which speaks Croatian) so - it is safer to use e.g. TO_DATE ('26.07.2021', 'DD.MM.YYYY')

Unable to Correct Oracle Error ORA-00905 Missing Keyword in SQL

I've been grinding on this small snippet of simple code for a day and can't find the issue causing the error. As the title states, I am getting error ORA-00905 Missing Keyword when trying to execute the following code:
SELECT DISTINCT DM.DESCRIPTION AS "AGENCY",
DM.DEPT_NO AS "DEPT NO",
CASE
WHEN VMP.RESERVE_DT IS NULL THEN
NULL
ELSE
VMP.RESERVE_DT
END AS "RESV_DT",
CASE
WHEN VMP.EST_PICKUP_DT IS NULL THEN
NULL
ELSE
VMP.EST_PICKUP_DT
END AS "EST_PKUP_DT",
CASE
WHEN VMP.EST_RETURN_DT IS NULL THEN
NULL
ELSE
VMP.EST_RETURN_DT
END AS "EST_RETN_DT",
VMP.EMP_NAME AS "EMPL_NAME",
VMP.UNIT_NO AS "UNIT_NUMBER",
VMP.RENTAL_CLASS_DESCRIPTION AS "RENT_CLS",
VMP.MP_TICKET_NO AS "MP_TKT_NO"
FROM DEPT_MAIN DM
INNER JOIN VIEW_MPOOL VMP ON VMP.DEPT_ID = DM.DEPT_ID
WHERE CASE
WHEN VMP.EST_PICKUP_DT IS NULL THEN
NULL
ELSE
TRUNC(VMP.EST_PICKUP_DT) = TRUNC(SYSDATE)
END
GROUP BY DM.DESCRIPTION,
DM.DEPT_NO,
CASE
WHEN VMP.RESERVE_DT IS NULL THEN
NULL
ELSE
VMP.RESERVE_DT
END,
CASE
WHEN VMP.EST_PICKUP_DT IS NULL THEN
NULL
ELSE
VMP.EST_PICKUP_DT
END,
CASE
WHEN VMP.EST_RETURN_DT IS NULL THEN
NULL
ELSE
VMP.EST_RETURN_DT
END,
VMP.EMP_NAME,
VMP.UNIT_NO,
VMP.RENTAL_CLASS_DESCRIPTION,
VMP.MP_TICKET_NO
ORDER BY CASE
WHEN VMP.EST_PICKUP_DT IS NULL THEN
NULL
ELSE
VMP.EST_PICKUP_DT
END ASC
The basis of this code was generated through an adhoc reporting program and was originally fully-qualified. I stripped out the extraneous quotation marks and assigned table aliases to clean it up. Though I hoped these efforts would help me find the issue, I am unable to find the cause. Thank you for your consideration.
Try to replace this :
WHERE
CASE
WHEN VMP.EST_PICKUP_DT IS NULL THEN NULL
ELSE TRUNC(VMP.EST_PICKUP_DT) = TRUNC(SYSDATE)
END
With :
WHERE
CASE
WHEN VMP.EST_PICKUP_DT IS NULL THEN NULL
ELSE TRUNC(VMP.EST_PICKUP_DT)
END
= TRUNC(SYSDATE)
Please note that this whole expression (and others similar in the query) could be simplified as as :
WHERE
TRUNC(VMP.EST_PICKUP_DT) = TRUNC(SYSDATE)
When VMP.EST_PICKUP_DT is NULL, TRUNC will return NULL, which will not be equal to TRUNC(SYSDATE).
Here:
WHERE
CASE
WHEN VMP.EST_PICKUP_DT IS NULL
THEN NULL
ELSE TRUNC(VMP.EST_PICKUP_DT) = TRUNC(SYSDATE)
END
The END is after a comparison and the case is not being compared against a value.
Switch it like:
WHERE
CASE
WHEN VMP.EST_PICKUP_DT IS NULL
THEN NULL
ELSE TRUNC(VMP.EST_PICKUP_DT)
END = TRUNC(SYSDATE)
Which as horse says, can just be simplified as
WHERE TRUNC(VMP.EST_PICKUP_DT) = TRUNC(SYSDATE)
since a NULL value on VMP.EST_PICKUP_DT will never match TRUNC(SYSDATE).
can't find the issue causing the error
Although I suppose that #EzLo and #a_horse_with_no_name maybe already found error in this case, I can propose a general procedure in debugging such queries.
Step 1: Debug your JOIN- and WHERE- predicates
Comment everything in your SELECT-statement, leave only JOINs, substitute fields with * or constant expression.
E.g.
SELECT 1
-- DISTINCT DM.DESCRIPTION AS "AGENCY",
-- DM.DEPT_NO AS "DEPT NO",
-- CASE
-- ....
-- VMP.RENTAL_CLASS_DESCRIPTION AS "RENT_CLS",
-- VMP.MP_TICKET_NO AS "MP_TKT_NO"
FROM DEPT_MAIN DM
INNER JOIN VIEW_MPOOL VMP ON VMP.DEPT_ID = DM.DEPT_ID
WHERE CASE
WHEN VMP.EST_PICKUP_DT IS NULL THEN
NULL
ELSE
TRUNC(VMP.EST_PICKUP_DT) = TRUNC(SYSDATE)
END
-- GROUP BY DM.DESCRIPTION,
-- ....
-- ORDER BY ..
In case of multiple complex predicates - uncomment one predicate at a time.
Step 2: Debug your GROUP BYs and HAVINGs
Uncomment GROUP BY section and edit fields section of your query.
If you have complex groupby's - uncomment by one field at time.
Start from simplest to complex
SELECT
DM.DESCRIPTION
,DM.DEPT_NO
-- ...
FROM DEPT_MAIN DM
INNER JOIN VIEW_MPOOL VMP ON VMP.DEPT_ID = DM.DEPT_ID
WHERE CASE
WHEN VMP.EST_PICKUP_DT IS NULL THEN
NULL
ELSE
TRUNC(VMP.EST_PICKUP_DT) = TRUNC(SYSDATE)
END
GROUP BY DM.DESCRIPTION
,DM.DEPT_NO
Copy-paste your GROUP BYs into SELECT fields section.
Step 3: Debug you aggregates, field transformation and renames
Now you have correct SELECT-query but probably not in the shape you want.
Step 4: Debug ORDER BYs
You have correct shape and in last step you need to ORDER BY your data.
If you have decent editor/IDE you can find source of error in 5-10 minutes even in cases of complex queries (and even RDBMS engine bugs)
P.S.
It's better to note which version of RDBMS you are using.

Using CASE statement name as another reference filed in another CASE statement

Is it possible to refer to another case statement name in another case statement within SQL query?
Example: I have 3 case statements. The first 2 case statements are returning values based off coded fields. My 3rd case statement I would like to refer to the ending case name to return a sum of quantity.
However, I cannot figure how to get the case statement to refer to the previous case names I created. I hope I am explaining this correctly.
Any assistance would be greatly appreciated. Please see attached image for more detail.
SELECT CI_ITEM.ITEMCODE
, CI_ITEM.ITEMCODEDESC
, CASE WHEN DATEDIFF("M",CI_ITEM.DATECREATED,GETDATE()) <60 THEN DATEDIFF("M",CI_ITEM.DATECREATED,GETDATE())
ELSE 60 END AS NO_OF_MONTHS
, CASE WHEN DATEDIFF("M",IM_ITEMTRANSACTIONHISTORY.TRANSACTIONDATE,GETDATE()) <=60
AND IM_ITEMTRANSACTIONHISTORY.TRANSACTIONCODE IN ('BI','II','SO','WI')
THEN IM_ITEMTRANSACTIONHISTORY.TRANSACTIONQTY *-1 ELSE '0' END AS QTY_CONSUMED_60_MONTHS
, CASE WHEN NO_OF_MONTHS = 0 THEN 0 ELSE SUM([QTY_CONSUMED_60_MONTHS])/ [NO_OF_MONTHS] END AS MONTHLY_AVE_ON_60MONTHS_DATA
FROM CI_ITEM
INNER JOIN IM_ITEMTRANSACTIONHISTORY ON CI_ITEM.ITEMCODE = IM_ITEMTRANSACTIONHISTORY.ITEMCODE
Simply wrap your dependent cases within a sub query and reference them as fields of the sub query result.
SELECT
*,
CASE WHEN NO_OF_MONTHS = 0 THEN 0 ELSE SUM([QTY_CONSUMED_60_MONTHS])/ [NO_OF_MONTHS] END AS MONTHLY_AVE_ON_60MONTHS_DATA
FROM
(
SELECT CI_ITEM.ITEMCODE
, CI_ITEM.ITEMCODEDESC
, CASE WHEN DATEDIFF("M",CI_ITEM.DATECREATED,GETDATE()) <60 THEN DATEDIFF("M",CI_ITEM.DATECREATED,GETDATE())
ELSE 60 END AS NO_OF_MONTHS
, CASE WHEN DATEDIFF("M",IM_ITEMTRANSACTIONHISTORY.TRANSACTIONDATE,GETDATE()) <=60
AND IM_ITEMTRANSACTIONHISTORY.TRANSACTIONCODE IN ('BI','II','SO','WI')
THEN IM_ITEMTRANSACTIONHISTORY.TRANSACTIONQTY *-1 ELSE '0' END AS QTY_CONSUMED_60_MONTHS
FROM CI_ITEM
INNER JOIN IM_ITEMTRANSACTIONHISTORY ON CI_ITEM.ITEMCODE = IM_ITEMTRANSACTIONHISTORY.ITEMCODE
)AS X

SQL simplifying case in case in case

I got the following SQL code (part of a select Statement):
Case
When HilfsTab2.Gruppe = 'HST' And Basis.Breite_FLA = Basis.Breite Then 0
Else Case When HilfsTab2.Gruppe = 'SA' Or HilfsTab2.Gruppe = 'HO / TB' Or
HilfsTab2.Gruppe = 'PR' Then 0 Else Case
When HilfsTab2.Gruppe Is Null Then -1 Else 1 End End
End As IsHST_Fluegel
Now, I run this over a table of several million entries. From my understanding, SQL checks the first case when for all rows, then the second for all entries and so on. This takes ages. Now I was thinking, there needs to be an easier way to do this.
I was thinking of a stored procedure / custom function that basically outputs -1, 0 or 1 depending on the entry.
Thanks in advance
For a possible speed improvement, do the NULL check first, the column comparison last and refactor to remove the nested CASE:
CASE WHEN HilfsTab2.Gruppe IS NULL
THEN -1
WHEN HilfsTab2.Gruppe IN ('SA', 'HO / TB', 'PR')
OR (HilfsTab2.Gruppe = 'HST' AND Basis.Breite_FLA = Basis.Breite)
THEN 0
ELSE 1
END AS IsHST_Fluegel
Your case could be simplified as:
Case
When HilfsTab2.Gruppe = 'HST' And Basis.Breite_FLA = Basis.Breite Then 0
When HilfsTab2.Gruppe in ('SA', 'HO / TB', 'PR') Then 0
When HilfsTab2.Gruppe Is Null Then -1
Else 1
End As IsHST_Fluegel
But this will not speed up your query. If you want to select millions of rows, it would take time anyway.

Select Logic in Query. Is this possible in Oracle?

Im trying to implement some sort of logic on the select statement of the query. I want it so that if no attribute is given, or if the inAttribute is 'NONE'; it will return the date and ALL of the values (compprice, compspread,price,spread,run).
If a value was given to in attribute then i want it to return the value it requested for (Refer to the case statement i tried to do).
Below is my attempt at it, and it is just not working. Any help please?
SELECT
mi.date,
IF inAttribute = '' THEN
mi.compprice,
mi.compspread,
mi.price,
mi.spread,
mi.run
ELSE
CASE inAttribute
WHEN 'CP' THEN mi.compprice,
WHEN 'CS THEN mi.compspread,
WHEN 'MP' THEN mi.price,
WHEN 'MS' THEN mi.spread,
WHEN 'R' THEN mi.run
END
END IF
FROM userValueTable mi
WHERE mi.index_family = inIdxFamily
AND mi.index_id = inIdxId
AND mi.date_>= inStartDate
AND mi.date_<= inEndDate
ORDER by mi.date_ ASC;
Few remarks You can't have variable column list from one line to another. '' is equal to NULL, comparing NULL with equality ( = ) is always false. you can have some fixed number of columns and set value of any column using CASE clause.
Oracle doesn't have an IF for SQL. Use CASE instead - it can act like a C/C#/Java/etc switch - case as you have it in your query, and it can also act like an if.
Also, as mentioned above:
You're stuck with returning a constant number of columns unless you use dynamic SQL
In Oracle, '' is treated as NULL so instead of = '' use IS NULL.
If you don't want to go to Dynamic SQL, you could add a "type" column to your select list and then null out any inapplicable values. Your downstream logic could pick the values to use (or ignore) based on the type. Here's an example:
SELECT
mi.date,
CASE
WHEN inAttribute IS NULL THEN 'inAttrNull'
ELSE 'inAttrNotNull'
END AS RecordType,
CASE WHEN inAttribute IS NULL THEN mi.compprice END AS compprice,
CASE WHEN inAttribute IS NULL THEN mi.compspread END AS compspread,
CASE WHEN inAttribute IS NULL THEN mi.price END AS price,
CASE WHEN inAttribute IS NULL THEN mi.spread END AS spread,
CASE WHEN inAttribute IS NULL THEN mi.run END AS run,
CASE inAttribute
WHEN 'CP' THEN mi.compprice
WHEN 'CS' THEN mi.compspread
WHEN 'MP' THEN mi.price
WHEN 'MS' THEN mi.spread
WHEN 'R' THEN mi.run
END AS SpecialValue
FROM userValueTable mi
... and your WHERE and ORDER BY clauses
You'll get a result set something like this:
RecordType compprice compspread price spread run specialvalue
------------- ---------- ---------- ---------- ---------- ---------- ------------
inAttrNotNull (null) (null) (null) (null) (null) 1234.56
inAttrNull 111.11 222.22 333.33 444.44 555.55 (null)
I know this isn't what you wanted, but it may be something you can work with as an alternative.
There is no IF in Oracle SQL, only in PL/SQL. You have to rewrite it to CASE. The same as you did in your query in ELSE part (you missed a single closing quote after 'CS' THEN...).
SELECT ...
(CASE WHEN inAttribute IS NULL THEN mi.compprice
WHEN .... THEN...
WHEN .... THEN...
...
ELSE ...
END) AS some_column_alias
FROM ...