combine OR and And Condtion without repeating in sql - sql

I'm trying to select phone number that is between date_from and date_to
or the date_to is null
but the problem in the Or part it neglects the other conditions (where pho.parent_id =:p_id and pho.phone_type='M' and rownum <=1 )
select pho.PHONE_NUMBER
from per_phones pho
where pho.parent_id = :p_id and
pho.phone_type='M'
and
rownum <=1 and sysdate > pho.DATE_FROM and sysdate < DATE_TO or DATE_TO is null;

Put your OR condition within braces
select pho.PHONE_NUMBER
from per_phones pho
where pho.parent_id = :p_id and pho.phone_type='M'
and rownum <=1 and
(sysdate > pho.DATE_FROM and sysdate < DATE_TO or DATE_TO is null)

I think your DATE_TO is null in case your record is valid from DATE_FROM till end of time.
You will still need to check DATE_FROM condition and also put rownum condition in the outer query so you need following:
Select PHONE_NUMBER from
(select pho.PHONE_NUMBER
from per_phones pho
where pho.parent_id = :p_id
and pho.phone_type='M'
and rownum <= 1 -- this is not needed here
and sysdate > pho.DATE_FROM
and (sysdate < DATE_TO or DATE_TO is null)
)
Where rownum <= 1
Cheers!!

Related

How to rewrite query to work without WITH syntax

just looking for some help on how to rewrite this query without WITH.
Im aware that i need to replace references to WITH-subqueries with the body of the subquery but im not exactly sure how. Thanks.
WITH current_employees AS (
SELECT DISTINCT emp_id
FROM appointment
WHERE end_date IS NULL
),
appointments_2015 AS (
SELECT a.emp_id, salary,
CASE WHEN start_date < '2015-01-01' THEN '2015-01-01' ELSE start_date END AS start_date,
CASE WHEN end_date < '2016-01-01' THEN end_date ELSE '2015-12-31' END AS end_date
FROM appointment a
JOIN current_employees ce ON a.emp_id = ce.emp_id
WHERE start_date < '2016-01-01' AND (end_date >= '2015-01-01' OR end_date IS NULL)
)
SELECT
emp_id,
SUM( salary * (end_date - start_date + 1) / 365 ) AS total
FROM appointments_2015
GROUP BY emp_id
As the CTEs are only referenced once, the change is pretty straight forward. For each CTE create a derived table (sometimes referred to as "inline view" or simply sub-select)
SELECT
emp_id,
SUM( salary * (end_date - start_date + 1) / 365 ) AS total
FROM (
SELECT a.emp_id, salary,
CASE WHEN start_date < '2015-01-01' THEN '2015-01-01' ELSE start_date END AS start_date,
CASE WHEN end_date < '2016-01-01' THEN end_date ELSE '2015-12-31' END AS end_date
FROM appointment a
JOIN (
SELECT DISTINCT emp_id
FROM appointment
WHERE end_date IS NULL
) current_employees ce ON a.emp_id = ce.emp_id
WHERE start_date < '2016-01-01' AND (end_date >= '2015-01-01' OR end_date IS NULL)
) appointments_2015
GROUP BY emp_id
You seem to want the salary in 2015 for current employees. If so:
SELECT a.emp_id,
SUM( salary * (end_date_2015 - start_date_2015 + 1) / 365 ) AS total
FROM (SELECT a.*,
(CASE WHEN start_date < '2015-01-01' THEN '2015-01-01'
WHEN start_date < '2016-01-01' THEN start_date
END) AS start_date_2015,
(CASE WHEN end_date < '2015-01-01' THEN NULL
WHEN end_date < '2016-01-01' THEN end_date
ELSE '2015-12-31'
END) AS end_date
FROM appointments_2015 a
) a
GROUP BY emp_id
HAVING COUNT(end_date) <> COUNT(*);

Is it possible to map multiple select statement into columns?

I have this table:
code(integer) |number_of_data(integer)| date (Date)
I need to:
Group by day, this for tho month of june only
Select sum of number_of_data for the day for each code != 0
Select n_data for code = 0
For the first 2 points I came up with:
select sum(number_of_data) nData, TO_CHAR(date, 'DD') dayOfMonth from T1
where to_char( date, 'mm') = 6
and code <> 0
group by TO_CHAR(date, 'DD') order by TO_CHAR(date, 'DD');
it gives me this table result:
nData | dayOfMonth
which is fine, anyway I'm missing requirement 3, whose query would be the same but with the opposite condition (code=0).
Is there a way to add it to the above query so to get this result:
nData | nDataZero | dayOfMonth
?
Whit some regards to the syntax in MS Sql. This is a way i would solve this in a oracle sql-like way:)
SELECT sum(nData) nData , sum(nDataZero) nDataZero, T1
from (
select sum(number_of_data) nData, 0 nDataZero , TO_CHAR(date, 'DD') dayOfMonth
from T1
where to_char( date, 'mm') = 6 and code <> 0
group by TO_CHAR(date, 'DD')
order by TO_CHAR(date, 'DD')
UNION
select 0 nData, sum(number_of_data) nDataZero , TO_CHAR(date, 'DD') dayOfMonth
from T1
where to_char( date, 'mm') = 6 and code == 0
group by TO_CHAR(date, 'DD')
order by TO_CHAR(date, 'DD'))
group by T1;
Rgds
Assuming that there will only be one entry with CODE = 0 for each day, then you can do:
SELECT SUM( CASE CODE WHEN 0 THEN NULL ELSE number_of_data END ) AS nData,
MAX( CASE CODE WHEN 0 THEN number_of_data END ) AS nDataZero,
EXTRACT( DAY FROM "Date" ) AS dayOfMonth
FROM T1
WHERE EXTRACT( MONTH FROM "Date" ) = 6
GROUP BY EXTRACT( DAY FROM "Date" )
ORDER BY EXTRACT( DAY FROM "Date" );
If there will be more than one entry then you will need to specify how it is to be handled (i.e. change MAX to SUM if you want the total of the CODE = 0 values).
You can use CASE to separate data into 2 slots, code=0 and code<>0:
select sum(number_of_data) nData, TO_CHAR(date, 'DD') dayOfMonth, CASE WHEN code = 0 THEN 0 ELSE 1 AS x
from T1
where to_char( date, 'mm') = 6
group by TO_CHAR(date, 'DD'), x
order by TO_CHAR(date, 'DD');

compare dates in oracle

For example I have in table row finish with values:
20-JAN-06;
21-SEP-06;
12-FEB-10;
15-MAR-09;
03-JUL-09;
23-JAN-09;
How can I compare them against sysdate? I know that this code is not correct:
Select name from project where finish <= sysdate ;
Why not use the ANSI standard CURRENT_TIMESTAMP?
SELECT * FROM SomeTable WHERE Finish <= CURRENT_TIMESTAMP;
Fiddle here
Something like that try cos I don't have oracle to test it
SELECT EMP_NAME, EMPNO
FROM EMP
WHERE TRUNC(START_DATE) = TRUNC(SYSDATE);
or
SELECT emp_name, empno
FROM emp
WHERE start_date >= TRUNC(SYSDATE)
and start_date < TRUNC(SYSDATE)+1
Select name
from project
where to_date(finish, 'DD-MON-YY') <= trunc(sysdate)

Combine two SQL statements, set a status

I currently have two SQL statements that I'd like to combine into one, and set a status if it meets each one. I've posted some massively stripped down code below:
select * from database where date1 < SYSDATE
select * from database where date2 < SYSDATE
Ideally, I'd like it so if it meets the criteria in the first statement, it'd set a flag of 'status1' and if it doesn't meet that criteria, but meets the second statement's criteria I'd like to set a flag of 'status2' - hope that makes sense!
For example the data would be like: Name | ID | Status
Thanks :)
Give this a shot:
select Name, ID, CASE
WHEN date1 < SYSDATE THEN 1
WHEN date2 < SYSDATE THEN 2
END as Status
from mytable
where date1 < SYSDATE or date2 < SYSDATE
select *
from (
select name, id, 'status1' as status
from some_table
where date1 < SYSDATE
UNION ALL
select name, id, 'status2'
from some_table
where date2 < SYSDATE
)
UPDATE mytable
SET flag =
CASE
WHEN date1 < SYSDATE THEN
'status1'
ELSE
'status2'
END
WHERE date1 < SYSDATE
OR
date2 < SYSDATE
Since you said you wanted to UPDATE the status...
UPDATE database
SET flag = CASE WHEN date1 < SYSDATE THEN 'status1' WHEN date2 < SYSDATE THEN 'status2' ELSE NULL END

Date Range in PL/SQL

If I have table with a Date column (Date field) called created_date, with values like "9/2/2010 5:25:42 PM".
I want to select all rows from a start_date to a end_date. However, the end_date may be null. In this case, I want to select all rows where created_date is greater than end_date.
Since toDate (which can be null) is a host variable, it's easier than the solutions already given (which are all wrong in that regard, btw)
select * from mytable
where created_date between v_fromdate
and nvl(v_todate, to_date('31.12.9999','dd.mm.yyyy'));
select *
from TABLE
where created_date >= '2010-09-02' and (created_date is NULL or created_date <= '2010-09-03')
Why just use a simple SQL query for that, like this one:
select xxx from table_names where created_date is null or (created_date >= to_date("02/09/2010", "dd/mm/yyyy") and created_date <= to_date("03/09/2010", "dd/mm/yyyy"));
Edit
You can define a query like the one defined by ammoQ, i.e. something like that:
select xxx from table_names where created_date is null or created_date >= start_date and created_date <= nvl(end_date, to_date("31/12/9999", "dd/mm/yyyy"));
However, as you are using PL/SQL, you can check the nullability of end_date parameter:
IF end_date IS NULL THEN
select xxx from table_names where created_date is null or created_date >= start_date;
ELSIF
select xxx from table_names where created_date is null or created_date >= start_date and created_date <= end_date;
END IF;
Note that you can remove the created_date is null condition if created_date is not a nullable column...
select * from yourtable
where created_date >= #StartDate AND created_date <=ISNULL(#EndDate,created_date)
SELECT *
FROM A_TABLE
WHERE CREATED_DATE >= &START_DATE AND
(CREATED_DATE <= &END_DATE OR
&END_DATE IS NULL)
If i took it right from your question
this should work:
SELECT *
FROM yourTable
WHERE created_date >= to_date('01.09.2010', 'dd.mm.yyyy')
AND (end_date <= to_date('02.09.2010', 'dd.mm.yyyy')
OR end_date IS NULL);