Combining two SQL SELECT statements on the same table - sql

I would like to combine these two SQL queries:
SELECT * FROM "Contracts" WHERE
"productType" = 'RINsell' AND
"clearTime" IS NULL AND
"holdTime" IS NOT NULL
ORDER BY "generationTime";
and
SELECT * FROM "Contracts" WHERE
"productType" = 'RINsell' AND
"clearTime" IS NULL AND
"holdTime" IS NULL
ORDER BY "contractLimitPrice";
When I run each statement, I get exactly the results I want, I would just like both results sequentially. My first thought was to use UNION ALL since this selections will be disjoint but I found that you can't use a UNION after an ORDER BY. I've searched quite a bit and most people suggest doing the ORDER BY after the UNION but each query has different ORDER BY conditions.

If you want the results of the first query before the results of the second, you can remove holdtime from the where clause, and use an order by like
order by
case when holdTime is not null then 0 else 1 end, --first query comes first
case when holdTime is not null --different orders for queries
then generationTime
else contractLimitPrice
end

... but I found that you can't use a UNION after an ORDER BY.
Well, you didn't look hard enough:
(
SELECT *
FROM "Contracts"
WHERE "productType" = 'RINsell'
AND "clearTime" IS NULL
AND "holdTime" IS NOT NULL
ORDER BY "generationTime"
)
UNION ALL
)
SELECT *
FROM "Contracts"
WHERE "productType" = 'RINsell'
AND "clearTime" IS NULL
AND "holdTime" IS NULL
ORDER BY "contractLimitPrice"
)
Note the parentheses. Per documentation:
(ORDER BY and LIMIT can be attached to a subexpression if it is
enclosed in parentheses. Without parentheses, these clauses will be
taken to apply to the result of the UNION, not to its right-hand input
expression.)
Closely related answer:
Sum results of a few queries and then find top 5 in SQL
Aside: I really would get rid of those CaMeL case identifiers. Your life is much easier with all-lower case legal identifiers in Postgres.

Related

SQL UNION vs OR, INTERSECT vs AND

I would like to know what the difference between an INTERSECT and an AND statement as well as a UNION statement and a OR statement is.
Is there a specific scenario where either one is recommended to use and can could I always use a OR/AND instead of an UNION/ INTERSECT ?
Use AND or OR between terms in a WHERE clause. If the complete boolean expression evaluates as true, then the row is included in the query's result set.
WHERE country = 'Canada' AND age > 21
Use INTERSECT or UNION between SELECT queries. If a row appears in both result sets, or either result set, respectively, then the row is included in the compound query's result set.
SELECT customer_id FROM archived_orders
UNION
SELECT customer_id FROM recent_orders

Do 'set operations' have an prescribed order of execution, or do they execute in order of evaluation?

Do set operations have a prescribed order of execution (e.g. first UNION, then MINUS, then INTERSECT), or do they execute in the order of which they are scripted and evaluated?
For example, let's say I want to have a starting cohort of customer_ids, then remove some, and then add some back in. Will the set operators execute here as Qry 1 minus Qry 2 union Qry 3?
select cust_id from tbl A
MINUS
select cust_id from tbl B where field = 'abc'
UNION
select cust_id from tbl A where field = 'xyz'
Since you didn't specify the RDBMS, I'll add SQL Server for completeness. This is the order of operations:
Expressions in parentheses
The INTERSECT operator
EXCEPT (equivalent of Oracle MINUS) and UNION evaluated from left to right based on their position in the expression
All set operators have equal precedence. The documentation says
If a SQL statement contains multiple set operators, then Oracle Database evaluates them from the left to right unless parentheses explicitly specify another order.
Well, not exactly "order of execution". SQL queries represent the result set.
They specify neither the exact operations being run nor the order of execution.
That said, there is an order of precedence for set operations. So, your query is going to be interpreted as:
(select cust_id from tbl A
MINUS
select cust_id from tbl B where field = 'abc'
)
UNION
select cust_id from tbl A where field = 'xyz'
This is specified by -- or more accurately, interpreted from -- the ANSI rules on set operations.
Just because the query is interpreted this way does not mean that it is executed this way.

getting same top 1 result in sql server

I have this query:
SELECT
IT_approvaldate
FROM
t_item
WHERE
IT_certID_fk_ind = (SELECT DISTINCT TOP 1 IT_certID_fk_ind
FROM t_item
WHERE IT_rfileID_fk = '4876')
ORDER BY
IT_typesort
Result when running this query:
I need get top 1 result. (2013-04-27 00:00:00) problem is when I select top 1, getting 2nd result.
I believe reason for that order by column value same in those two result.
please see below,
However I need get only IT_approvaldate column top 1 as result of my query.
How can I do this? Can anyone help me to solve this?
Hi use below query and check
SELECT IT_approvaldate FROM t_item WHERE IT_certID_fk_ind =(SELECT DISTINCT top 1 IT_certID_fk_ind FROM t_item WHERE IT_rfileID_fk ='4876' ) and IT_approvaldate is not null ORDER BY IT_typesort
This will remove null values from the result
If you want NULL to be the last value in the sorted list you can use ISNULL in ORDER BY clause to replace NULL by MAX value of DATETIME
Below code might help:
SELECT TOP 1 IT_approvaldate
FROM t_item
WHERE IT_certID_fk_ind = (SELECT DISTINCT top 1 IT_certID_fk_ind FROM t_item WHERE IT_rfileID_fk ='4876' )
ORDER BY IT_typesort ASC, ISNULL(IT_approvaldate,'12-31-9999 23:59:59') ASC;
TSQL Select queries are not inherently deterministic. You must add a tie-breaker or by another row that is not.
The theory is SQL Server will not presume that the NULL value is greater or lesser than your row, and because your select statement is not logically implemented until after your HAVING clause, the order depends on how the database is setup.
Understand that SQL Server may not necessarily choose the same path twice unless it thinks it is absolutely better. This is the reason for the ORDER BY clause, which will treat NULLs consistently (assuming there is a unique grouping).
UPDATE:
It seemed a good idea to add a link to MSDN's documentation on the ORDER BY. Truly, it is good practice to start from the Standard/MSDN. ORDER BY Clause - MSDN

Oracle Order by not working for Subquery from DUAL

Hi all when I executed this query somehow its throwing the following error -
ORA-00907: missing right parenthesis.
But if you remove the order by 1 from SELECT 2 FROM DUAL order by 1 its working.
Did I miss something out here or its ORACLE limitation
SELECT (CASE
WHEN EXISTS
(SELECT 1 FROM DUAL) THEN
(SELECT 4
FROM dual)
ELSE
(SELECT 2 FROM DUAL order by 1 )
END) AS DELEGATOR FROM dual
Below is a working code with order by 1 removed
SELECT (CASE
WHEN EXISTS
(SELECT 1 FROM DUAL) THEN
(SELECT 4
FROM dual)
ELSE
(SELECT 2 FROM DUAL )
END) AS DELEGATOR FROM dual
Somehow I already give up but when I change the code to this
it somehow works. I applied to my actual query and the result
are the expected outcome.
SELECT (CASE
WHEN EXISTS
(SELECT 1 FROM DUAL) THEN
(SELECT 4
FROM dual)
ELSE
(select * from (SELECT 2 FROM DUAL order by 1 )
where rownum = 1)
END) AS DELEGATOR FROM dual
SELECT 2 FROM DUAL order by 1
Firstly, an ORDER BY makes no sense here the query returns just one row.
Secondly, you cannot use an order by in a Scalar Subquery Expression when there is no sense of ordering the rows. Order by would be allowed in certain cases where the outer query expects an ordered set of rows. In your case, there is no question of getting more than a single-row.
Thirdly, it is not a good practice coding as order by 1,2 etc. Instead, use the appropriate column name. You might not come to know if the columns in the select list changes, your result set would be then ordered differently and you will need to make changes at both the places.
A scalar subquery expression returns exactly one column value from one row. If the expression returned more than one row you would get an error, "ORA-01427: single-row subquery returns more than one row". As it can only have a single value, ordering that value would be meaningless.
The missing-right-parenthesis error doesn't necessarily mean you have unbalanced parentheses, it can indicate other errors that have made the parser give up at the point it expected to see one. Here the parser expected the subquery's closing parenthesis to have come after the FROM DUAL, so it's stopping when it doesn't see one - effectively it doesn't know how to interpret the rest of the statement so it doesn't try (hugely oversimplifying).
An order by clause isn't meaningful in a subquery, and generally isn't allowed; though it is tolerated in some places, such as an inline view, despite still having no effect.
Obviously your example is very contrived, but there is a scenario where you might think you want an order by clause, and that is to get the first value from a result set which you need to be ordered. Based on how limit works in other databases you might try to do something like:
select (
select object_name from user_objects
where rownum = 1
order by created desc
)
from dual
... but that isn't how rownum works, and would also get ORA-00907. If that is what you're doing you would need another layer of subquery (as an inline view now) which can be ordered, and apply the rownum filter to that:
select (
select object_name from (
select object_name from user_objects
order by created desc
)
where rownum = 1
)
from dual
... which is now valid.
(Whether you actually need to be doing that in a subquery, rather than through a join, is another matter - your query is hopefully complicated enough to warrant it).

Different results from using IN and EXISTS

I have a query that has been giving me fits. Basically I want a left outer join, but without using a join.
I started off using IN and got back about 13,000 rows. If I use EXISTS, I then get about 11,000 rows. Even if I use GROUP BY to make sure duplicates aren't counted, there's still a difference.
Here's some code
This one with exists
SELECT upper(EMAIL_ADDRESS)
FROM DATA.CRM_CONTACTS
WHERE EXISTS
(
SELECT upper(Email_address)
FROM DATA.MMBI
WHERE DATA.CRM_CONTACTS.Email_address = DATA.MMBI.Email_Address
)
group by 1
order by 1
And this is code that uses IN:
SELECT upper(EMAIL_ADDRESS)
FROM DATA.CRM_CONTACTS
WHERE upper(EMAIL_ADDRESS) IN
(
SELECT upper(Email_address)
FROM DATA.MMBI
)
group by 1
order by 1
Is there any reason that would explain why I'm getting different results?
Assuming that you're using SQL Server:
In your in case, you're making a case-insensitive comparison, uppercasing both values to be compared:
WHERE upper(EMAIL_ADDRESS) IN ( SELECT upper(Email_address)
FROM DATA.MMBI
)
In your exists case, your join criteria for the correlated subquery is this
WHERE DATA.CRM_CONTACTS.Email_address = DATA.MMBI.Email_Address
Which means it's going to use the collation in play to make the comparison, which might be case-sensitive.