multiple conditions in oracle case with one :PAR - sql

I have a more complex query, but I will give a simple example. In SSRS same input but need different outputs:
select * from myTable where
case
when :PAR1 = 'hour' then myTable.hour = :PAR1
when :PAR1 = 'Mounth' then myTable.Mounth = :PAR1
end
How to make it?
I'm try to
case length(:PAR1)
when 18 then hour: = PAR1
..
always a mistake..

You don't need a CASE expression here:
SELECT *
FROM myTable
WHERE (:PAR1 = 'hour' AND hour = :PAR1) OR
(:PAR1 = 'Mounth' AND Mounth = :PAR1);

Code you posted doesn't make sense to me; are you sure that :PAR1 is used everywhere? I'd expect something like this instead
select *
from mytable
where (:PAR1 = 'hour' and hour = :PAR2)
or (:PAR1 = 'Mounth' and mounth = :PAR2)
-------
maybe not :PAR2, but
certainly not :PAR1
Also, when you're dealing with hours, what is mounth? Shouldn't that be month?

Related

I am trying to convert Oracle view into SQL, but i am having issue with query performance

Oracle
(TO_CHAR(P.EstimatedInServiceDate, 'YYYY') =
(SELECT SUBSTR(ConfigurationValue, -4)
FROM PETE.vw_Configuration
WHERE configurationkey = 'CurrentPATYear'))
SQL - I tried to convert above code it is returning a data fine but my query is taking too long to run because of this particular chunk. If any better way to do this please let me know.
(Cast(DatePart(Year,P.EstimatedInServiceDate)as varchar) =
(SELECT right(ConfigurationValue, 4)
FROM Configuration
WHERE configurationkey = 'CurrentPATYear'))
You can use datepart() only :
where datepart(year, P.EstimatedInServiceDate) = (SELECT right(ConfigurationValue, 4)
FROM Configuration
WHERE configurationkey = 'CurrentPATYear')
)
It's a poor practice in SQL Server (or Oracle) to apply expressions to table columns in a WHERE-clause, as it makes the expression non-Sargable.
Instead write this something like:
P.EstimatedInServiceDate >=
(SELECT ConfigurationValue
FROM Configuration
WHERE configurationkey = 'CurrentPATYear')
and
P.EstimatedInServiceDate < dateadd(year,1,
(SELECT ConfigurationValue
FROM Configuration
WHERE configurationkey = 'CurrentPATYear'))

how do I join two tables sql

I have an issue that I'm hoping you can help me with. I am trying to create charting data for performance of an application that I am working on. The first step for me to perform two select statements with my feature turned off and on.
SELECT onSet.testName,
avg(onSet.elapsed) as avgOn,
0 as avgOff
FROM Results onSet
WHERE onSet.pll = 'On'
GROUP BY onSet.testName
union
SELECT offSet1.testName,
0 as avgOn,
avg(offSet1.elapsed) as avgOff
FROM Results offSet1
WHERE offSet1.pll = 'Off'
GROUP BY offSet1.testName
This gives me data that looks like this:
Add,0,11.4160277777777778
Add,11.413625,0
Delete,0,4.5245277777777778
Delete,4.0039861111111111,0
Evidently union is not the correct feature. Since the data needs to look like:
Add,11.413625,11.4160277777777778
Delete,4.0039861111111111,4.5245277777777778
I've been trying to get inner joins to work but I can't get the syntax to work.
Removing the union and trying to put this statement after the select statements also doesn't work. I evidently have the wrong syntax.
inner join xxx ON onSet.testName=offset1.testName
After getting the data to be like this I want to apply one last select statement that will subtract one column from another and give me the difference. So for me it's just one step at a time.
Thanks in advance.
-KAP
I think you can use a single query with conditional aggregation:
SELECT
testName,
AVG(CASE WHEN pll = 'On' THEN elapsed ELSE 0 END) AS avgOn,
AVG(CASE WHEN pll = 'Off' THEN elapsed ELSE 0 END) AS avgOff
FROM Results
GROUP BY testName
I just saw the filemaker tag and have no idea if this work there, but on MySQL I would try something along
SELECT testName, sum(if(pll = 'On',elapsed,0)) as sumOn,
sum(if(pll = 'On',1,0)) as numOn,
sum(if(pll ='Off',elapsed,0)) as sumOff,
sum(if(pll ='Off',1,0)) as numOff,
sumOn/numOn as avgOn,
sumOff/numOff as avgOff
FROM Results
WHERE pll = 'On' or pll='Off'
GROUP BY testName ;
If it works for you then this should be rather efficient as you do not need to join. If not, thumbs pressed that this triggers another idea.
The difficulty you have with the join you envisioned is that the filtering in the WHERE clause is performed after the join was completed. So, you would still not know what records to use to compute the averages. If the above is not implementable with FileMaker then check if nested queries work. You would then
SELECT testName, on.avg as avgOn, off.avg as avgOff
FROM ( SELECT ... FROM Results ...) as on, () as off
JOIN on.testName=off.testName
If that is also not possible then I would look for temporary tables.
OK guys... thanks for the help again. Here is the final answer. The statement below is FileMaker custom function that takes 4 arguments (platform, runID, model and user count. You can see the sql statement is specified. FileMaker executeSQL() function does not support nested select statements, does not support IF statements embedded in select statements (calc functions do of course) and finally does not support the SQL keyword VALUES. FileMaker does support the SQL keyword CASE which is a little more powerful but is a bit wordy. The select statement is in a variable named sql and result is placed in a variable named result. The ExecuteSQL() function works like a printf statement for param text so you can see the swaps do occur.
Let(
[
sql =
"SELECT testName, (sum( CASE WHEN PLL='On' THEN elapsed ELSE 0 END)) as sumOn,
sum( CASE WHEN PLL='On' THEN 1 ELSE 0 END) as countOn,
sum( CASE WHEN PLL='Off' THEN elapsed ELSE 0 END) as sumOff,
sum( CASE WHEN PLL='Off' THEN 1 ELSE 0 END) as countOff
FROM Results
WHERE Platform = ?
and RunID = ?
and Model = ?
and UserCnt = ?
GROUP BY testName";
result = ExecuteSQL ( sql ; "" ; ""
; platform
; runID
; model
; userCnt )
];
getAverages ( Result ; "" ; 2 )
)
For those interested the custom function looks like this:
getAverages( result, newList, pos )
Let (
[
curValues = Substitute( GetValue( data; pos ); ","; ¶ );
sumOn = GetValue( curValues; 2 ) ;
countOn = GetValue( curValues; 3 );
sumOff = GetValue( curValues; 4 );
countOff = GetValue( curValues; 5 );
avgOn = sumOn / countOn;
avgOff = sumOff / countOff
newItem = ((avgOff - avgOn) / avgOff ) * 100
];
newList & If ( pos > ValueCount( data); newList;
getAverages( data; If ( not IsEmpty( newList); ¶ ) & newItem; pos + 1 ))
)

change where condition based on column value

I faced the following requirement. The following query is called by a procedure. The value p_pac_code is the input parameter of the procedure.
The requirement is the query should have an additional condition sp_sbsp.SUBSPCLTY_CODE!='C430 if the p_pac_code value is '008'.
For any other p_pac_code value, it should run as it is below. Is there way to do this by adding an additional condition in the WHERE clause?
As for now, I have done this using IF.....ELSE using the query two times separately depending on p_pac_code value. But I am required to find a way to do with just adding a condition to this single query.
SELECT ptg.group_cid
FROM PRVDR_TYPE_X_SPCLTY_SUBSPCLTY ptxss,
PT_X_SP_SSP_STATUS pxsst ,
pt_sp_ssp_x_group ptg,
group_x_group_store gg,
specialty_subspecialty sp_sbsp,
treatment_type tt,
provider_type pt
WHERE
pt.PRVDR_TYPE_CODE = ptxss.PRVDR_TYPE_CODE
AND tt.TRTMNT_TYPE_CODE = pxsst.TRTMNT_TYPE_CODE
AND ptxss.PRVDR_TYPE_X_SPCLTY_SID = pxsst.PRVDR_TYPE_X_SPCLTY_SID
AND tt.TRTMNT_TYPE_CODE = p_pac_code
AND TRUNC(SYSDATE) BETWEEN TRUNC(PXSST.FROM_DATE) AND TRUNC(PXSST.TO_DATE)
AND ptg.prvdr_type_code =ptxss.prvdr_type_code
AND ptg.spclty_subspclty_sid = ptxss.spclty_subspclty_sid
AND ptxss.spclty_subspclty_sid = sp_sbsp.spclty_subspclty_sid
AND ptg.spclty_subspclty_sid = sp_sbsp.spclty_subspclty_sid
AND ptg.status_cid = 2
AND ptg.group_cid = gg.group_cid
AND gg.group_store_cid = 16
AND gg.status_cid = 2;
Thanks in advance.
You can simply add a condition like this:
... and (
( sp_sbsp.SUBSPCLTY_CODE!='C430' and p_pac_code = '008')
OR
NVL(p_pac_code, '-') != '008'
)
This can be re-written in different ways, this one is quite self-explanatory
Just add:
AND NOT ( NVL( sp_sbsp.SUBSPCLTY_CODE, 'x' ) = 'C430'
AND NVL( p_pac_code value, 'x' ) = '008' )
to the where clause.
The NVL function is used so that it will match NULL values (if they exist in your data); otherwise, even though NULL does not match C430 you will still find that NULL = 'C430' and NULL <> 'C430' and NOT( NULL = 'C430' ) will all return false.
Quite easy. Add the following condition:
AND (sp_sbsp.SUBSPCLTY_CODE != 'C430' OR p_pac_code value != '008')
(don't forget the parenthesis)
Just sharing
SELECT ptg.group_cid
FROM PRVDR_TYPE_X_SPCLTY_SUBSPCLTY ptxss
WHERE
pt.PRVDR_TYPE_CODE = ptxss.PRVDR_TYPE_CODE
&&((tt.TRTMNT_TYPE_CODE = pxsst.TRTMNT_TYPE_CODE)
or (tt.TRTMNT_TYPE_CODE = pxsst.TRTMNT_TYPE_CODE))
just use the parenthesis to specify where the conditionmust implement.

Need to optimize a SQL Query

Here is the where clause of the SQL. when I'm removing this part, it's taking 3 mins to execute, with this one it's taking more than 15 mins
there are almost 9000 records in DB
WHERE username = 'xyz' AND
(
( acceptedfordeliverytime BETWEEN '2012-9-1' AND '2013-1-29' )
OR
(
YEAR(acceptedfordeliverytime) = YEAR('2013-1-29')
AND
MONTH(acceptedfordeliverytime) = MONTH('2013-1-29')
AND
DAY(acceptedfordeliverytime) = DAY('2013-1-29')
)
OR
(
YEAR(acceptedfordeliverytime) = YEAR('2012-9-1')
AND
MONTH(acceptedfordeliverytime) = MONTH('2012-9-1')
AND
DAY(acceptedfordeliverytime) = DAY('2012-9-1')
)
)
Why don't you just use:
WHERE username = 'xyz' AND
(acceptedfordeliverytime >= '2012-09-01' AND
acceptedfordeliverytime < '2013-01-30'
)
This will also allow an index on (username, acceptedfordeliverytime) to be used when executing the query.
I think this will give you the same results.
and also make an index for column acceptedfordeliverytime to speed up searching.
WHERE username = 'xyz' AND acceptedfordeliverytime BETWEEN '2012-9-1' AND '2013-1-29'
Isn't BETWEEN inclusive? This would mean that you don't need all the extra clauses (that check for the first and last date in a VERY elaborate way). I believe your query would return the same result if you just did:
WHERE username = 'xyz' AND
(
acceptedfordeliverytime BETWEEN '2012-9-1' AND '2013-1-29'
)
Your both OR part is unnecessary.
when you use
acceptedfordeliverytime Between '2012-9-1' AND '2013-1-29'
It used both date included so OR part is not needed. if you have date and time in your database then you can convert it into date like this
CAST(acceptedfordeliverytime as date) Between '2012-9-1' AND '2013-1-29'

ORA-01861 literal does not match format string on SELECT statement

Good day.
I am executing a query and encountering:
ORA-01861 literal does not match format string error.
I executed this query and IT WORKED.
SELECT * FROM GCACC_OPERATION_DETAIL WHERE id_notice in (75078741)
AND id_analytical_center in (100000002)
AND interface_date = '2013-06-30'
AND generic_client = 'someGenClient'
AND document_class = 'DOCCLA0001'
AND accounting_tag_identifier = 1
AND generated_actual_acc_doc
IN (select id_accounting_document
from gcacc_accounting_document
where document_status = 'DOCSTA0001');
My other query is written below which DID NOT WORK.
SELECT * FROM GCACC_OPERATION_DETAIL WHERE id_notice IN (75078741)
AND id_analytical_center in (100000002)
AND generic_client = 'someGenClient'
AND document_class = 'DOCCLA0001'
AND accounting_tag_identifier = 1
AND interface_date = '2013-06-30'
AND ind_pending_process = 1
AND operation_type
IN (select cod_develop from gcacc_operation_type where ind_operation = 'B');
This is really weird because the error happens in the date part but I am writing the same syntax for the date part. I maybe missing something silly here and fresher eyes are needed. Thanks in advance!
I don't know what the specific problem is, but assuming "interface_date" is a DATE type, it is bad practice to use literals in a query for a date. This makes the assumption that the default NLS_DATE_FORMAT agrees with your date literal. That will come back to bite you. To ensure that your date constraint is portable, change to this:
AND interface_date = to_date('2013-06-30','YYYY-MM-DD')