when with X as () compute? and about left join - sql

hi i have 3 questions on sql please :
1-about this simple code
1. with cte as (
2. select * from TABLE1)
3. select * from cte
when select * from TABLE1 compute?
first the line 3 call and then line 1 then line 2
or first 1+2 and then 3?
2- when i do left/right join i have got some row with null, that make sense .
but how can i insert to the row will null "0" instead null?
to all of the row that because the left/right join get null ( if i use inner join i will not show this row )
thanks!

The order of execution is up to the database. The order of execution will depend on tables statistics and other factors. I've seen both order of execution.
If you have a NULL value and you want to show zero, use NVL for Oracle, e.g. NVL(myColumn,0) this will return myColumn if it's not null, otherwise 0. ISNULL for SQL Server and MySQL.

Related

Oracle: filter all rows before the ID

I have a big query that brings me a lot of rows, and based on each row I use this another query as a subselect.
This subselect brings me the following result rest on Oracle:
SELECT oc3.ID_ORGAO_INTELIGENCIA,
oc3.ord,
lag(oc3.ID_ORGAO_INTELIGENCIA, 1, NULL) OVER (
ORDER BY oc3.ord) ultimo
FROM
( SELECT DISTINCT oc2.*
FROM
( SELECT oc1.ID_ORGAO_INTELIGENCIA,
oc1.ID_ORGAO_INTELIGENCIA_PAI,
oc1.SG_ORGAO_INTELIGENCIA,
rownum AS ord
FROM TB_ORGAO_INTERNO oc1
WHERE oc1.DH_EXCLUSAO IS NULL START WITH oc1.ID_ORGAO_INTELIGENCIA =
-- this is a value that come from an outer select
-- If I put the value directly, like: S.ID_ORGAO_INTELIGENCIA, it does not work... I dont know why...
(SELECT sa.ID_ORGAO_INTELIGENCIA
FROM TB_SOLICITACAO sa
WHERE sa.ID_SOLICITACAO = 1077)-- s.ID_SOLICITACAO)
CONNECT BY
PRIOR oc1.ID_ORGAO_INTELIGENCIA_PAI = oc1.ID_ORGAO_INTELIGENCIA) oc2
INNER JOIN TB_PERMISSAO pe2_ ON pe2_.ID_ORGAO_INTELIGENCIA = oc2.ID_ORGAO_INTELIGENCIA
INNER JOIN TB_USUARIO u_ ON u_.ID_USUARIO = pe2_.ID_USUARIO
WHERE pe2_.ID_STATUS_PERMISSAO = 7
AND pe2_.ID_ATRIBUICAO IN :atribuicoes
ORDER BY oc2.ord) oc3
The result:
That important value from each row is the S.ID_SOLICITACAO, because based on that value that the subquery will be started.
I need to be able to filter the results by oc3.ID_ORGAO_INTELIGENCIA where it brings me all the rows before that number.
So, If I filter by 430, only the row with 311 will return.
If I filter by 329, it will bring me the: 311 and 430.
Is there a way to achieve this result?
One option might be to use your current query as a CTE, and then filter data it returns. Something like this:
with ycq as
-- your current query
(select ...
from ...
)
select *
from ycq a
where a.ord < (select b.ord
from ycq b
where b.id_orgao_inteligencia = :par_id_orgao_inteligencia
);

Order by data as per supplied Id in sql

Query:
SELECT *
FROM [MemberBackup].[dbo].[OriginalBackup]
where ration_card_id in
(
1247881,174772,
808454,2326154
)
Right now the data is ordered by the auto id or whatever clause I'm passing in order by.
But I want the data to come in sequential format as per id's I have passed
Expected Output:
All Data for 1247881
All Data for 174772
All Data for 808454
All Data for 2326154
Note:
Number of Id's to be passed will 300 000
One option would be to create a CTE containing the ration_card_id values and the orders which you are imposing, and the join to this table:
WITH cte AS (
SELECT 1247881 AS ration_card_id, 1 AS position
UNION ALL
SELECT 174772, 2
UNION ALL
SELECT 808454, 3
UNION ALL
SELECT 2326154, 4
)
SELECT t1.*
FROM [MemberBackup].[dbo].[OriginalBackup] t1
INNER JOIN cte t2
ON t1.ration_card_id = t2.ration_card_id
ORDER BY t2.position DESC
Edit:
If you have many IDs, then neither the answer above nor the answer given using a CASE expression will suffice. In this case, your best bet would be to load the list of IDs into a table, containing an auto increment ID column. Then, each number would be labelled with a position as its record is being loaded into your database. After this, you can join as I have done above.
If the desired order does not reflect a sequential ordering of some preexisting data, you will have to specify the ordering yourself. One way to do this is with a case statement:
SELECT *
FROM [MemberBackup].[dbo].[OriginalBackup]
where ration_card_id in
(
1247881,174772,
808454,2326154
)
ORDER BY CASE ration_card_id
WHEN 1247881 THEN 0
WHEN 174772 THEN 1
WHEN 808454 THEN 2
WHEN 2326154 THEN 3
END
Stating the obvious but note that this ordering most likely is not represented by any indexes, and will therefore not be indexed.
Insert your ration_card_id's in #temp table with one identity column.
Re-write your sql query as:
SELECT a.*
FROM [MemberBackup].[dbo].[OriginalBackup] a
JOIN #temps b
on a.ration_card_id = b.ration_card_id
order by b.id

Sum Distinct By Other Column

I have a problem with PL/SQL since i am new in PL/SQL world.
Let's say i have table like this.
COlumnA COlumnB COlumnC
1 5000000000 X
1 5000000000 X
2 4350000000 X
2 4350000000 X
3 10000000000 X
3 10000000000 X
3 10000000000 X
4 1809469720 Y
5 10000000000 X
5 10000000000 X
6 3000000000 X
6 3000000000 X
And i want to produce select statement as below.
ColumnC |Sum
X |32350000000
Y |1809469720
I have solved this problem in Oracle 12c with inner query, but when the system need to go to Oracle 11g, my query doesn't work anymore, i need to have the expected result with only one select statement.
Could anyone please advise?
Thank you!
This is what I came up with... using an inline view rather than a correlated subquery in the SELECT list.
SELECT d.columnc AS "ColumnC"
, SUM(d.columnb) AS "Sum"
FROM ( SELECT t.columna
, t.columnb
, t.columnc
FROM tablea t
GROUP
BY t.columna
, t.columnb
, t.columnc
) d
GROUP
BY d.columnc
This uses an inline view (aliased as "d") to return a "distinct" set of rows from tablea. We can get a distinct set, using a GROUP BY clause, or including the DISTINCT keyword, or even by writing a query that uses a UNION set operator.
Just wrap that query in parens, assign an alias, and use it in the FROM clause, as if it were a table or view.
The statement operates similarly to referencing a VIEW in the FROM clause.
You don't need to do this, but to illustrate how the query above operates. We could create a view, like this:
CREATE VIEW d AS
SELECT t.columna
, t.columnb
, t.columnc
FROM tablea t
GROUP
BY t.columna
, t.columnb
, t.columnc
And then we can reference the view in the FROM clause of another query, for example
SELECT d.columnc AS "ColumnC"
, SUM(d.columnb) AS "Sum"
FROM d
GROUP
BY d.columnc
But we don't actually need to create the VIEW object. We can include the view query as an "inline view".
I don't believe that Oracle 11g has a restriction on the nesting of inline views to three levels. I suspect that the restriction you are running into is related to correlated subqueries. The subquery can reference columns from the outer query, but only up one level... columns from the query it's used in. It can't reference columns in a query that is further out. (I've not confirmed with testing, but that's my recollection.)
This is where the actual ORA- and/or PLS- error message from Oracle would be of some help in identifying the restriction you are running into.
First find the distinct values of COlumnA,COlumnB and COlumnC then do the aggregation
Try this
select COlumnC,sum(COlumnB) from
(
select distinct COlumnA,COlumnB,COlumnC
from Table1
)
Group by COlumnC
Or you can simple use this query.
Select sum(columnB) as sum,columnC from table_name group by ColumnC;

Returning the lowest integer not in a list in SQL

Supposed you have a table T(A) with only positive integers allowed, like:
1,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18
In the above example, the result is 10. We always can use ORDER BY and DISTINCT to sort and remove duplicates. However, to find the lowest integer not in the list, I came up with the following SQL query:
select list.x + 1
from (select x from (select distinct a as x from T order by a)) as list, T
where list.x + 1 not in T limit 1;
My idea is start a counter and 1, check if that counter is in list: if it is, return it, otherwise increment and look again. However, I have to start that counter as 1, and then increment. That query works most of the cases, by there are some corner cases like in 1. How can I accomplish that in SQL or should I go about a completely different direction to solve this problem?
Because SQL works on sets, the intermediate SELECT DISTINCT a AS x FROM t ORDER BY a is redundant.
The basic technique of looking for a gap in a column of integers is to find where the current entry plus 1 does not exist. This requires a self-join of some sort.
Your query is not far off, but I think it can be simplified to:
SELECT MIN(a) + 1
FROM t
WHERE a + 1 NOT IN (SELECT a FROM t)
The NOT IN acts as a sort of self-join. This won't produce anything from an empty table, but should be OK otherwise.
SQL Fiddle
select min(y.a) as a
from
t x
right join
(
select a + 1 as a from t
union
select 1
) y on y.a = x.a
where x.a is null
It will work even in an empty table
SELECT min(t.a) - 1
FROM t
LEFT JOIN t t1 ON t1.a = t.a - 1
WHERE t1.a IS NULL
AND t.a > 1; -- exclude 0
This finds the smallest number greater than 1, where the next-smaller number is not in the same table. That missing number is returned.
This works even for a missing 1. There are multiple answers checking in the opposite direction. All of them would fail with a missing 1.
SQL Fiddle.
You can do the following, although you may also want to define a range - in which case you might need a couple of UNIONs
SELECT x.id+1
FROM my_table x
LEFT
JOIN my_table y
ON x.id+1 = y.id
WHERE y.id IS NULL
ORDER
BY x.id LIMIT 1;
You can always create a table with all of the numbers from 1 to X and then join that table with the table you are comparing. Then just find the TOP value in your SELECT statement that isn't present in the table you are comparing
SELECT TOP 1 table_with_all_numbers.number, table_with_missing_numbers.number
FROM table_with_all_numbers
LEFT JOIN table_with_missing_numbers
ON table_with_missing_numbers.number = table_with_all_numbers.number
WHERE table_with_missing_numbers.number IS NULL
ORDER BY table_with_all_numbers.number ASC;
In SQLite 3.8.3 or later, you can use a recursive common table expression to create a counter.
Here, we stop counting when we find a value not in the table:
WITH RECURSIVE counter(c) AS (
SELECT 1
UNION ALL
SELECT c + 1 FROM counter WHERE c IN t)
SELECT max(c) FROM counter;
(This works for an empty table or a missing 1.)
This query ranks (starting from rank 1) each distinct number in ascending order and selects the lowest rank that's less than its number. If no rank is lower than its number (i.e. there are no gaps in the table) the query returns the max number + 1.
select coalesce(min(number),1) from (
select min(cnt) number
from (
select
number,
(select count(*) from (select distinct number from numbers) b where b.number <= a.number) as cnt
from (select distinct number from numbers) a
) t1 where number > cnt
union
select max(number) + 1 number from numbers
) t1
http://sqlfiddle.com/#!7/720cc/3
Just another method, using EXCEPT this time:
SELECT a + 1 AS missing FROM T
EXCEPT
SELECT a FROM T
ORDER BY missing
LIMIT 1;

NOT IN vs NOT EXISTS and select 1 1?

I am very much a beginner and I completely get what NOT IN does, but don't really get EXISTS or NOT EXISTS.
Even more, I don't understand what this does:
SELECT TOP 1 1
FROM tblSomeTable
What does this query actually do?
For reference, I have been working with something like this:
SELECT COUNT(E_ID)
FROM tblEmployee e
INNER JOIN tblManager m
ON e.tbl_ID = m.tbl_ID
WHERE NOT EXISTS(SELECT TOP 1 1
FROM tblEmployee e2
WHERE e2.E_ID = e.E_ID
AND isFired = 'N'
)
I suppose I haven't read/seen a layman's explanation yet that makes sense to me. Even after reading Diff between Top 1 1 and Select 1 in SQL Select Query I still don't get it
The question that I think would actually need answering is whether EXISTS (SELECT TOP 1 1 FROM MyTable) is actually necessary.
Top 1 1 is telling the query to pick the constant "1" for any answer.
The Top 1 part is telling it to stop as soon as it finds a match and returns "1".
Wouldn't EXISTS (SELECT TOP 1 FROM MyTable) be sufficient?
Your first query will get you only top most record (very first record) out of the total rows in result set. So, if your query returns 10 rows .. you will get the first row. Read more about TOP
SELECT TOP 1 FROM tblSomeTable
In your Second query the part under () is a subquery, in your case it's a correlated subquery which will be evaluated once for each row processed by the outer query.
NOT EXISTS will actually check for existence of the rows present in subquery
WHERE NOT EXISTS
(
SELECT TOP 1 1 FROM tblEmployee e2 WHERE e2.E_ID = e.E_ID AND isFired = 'N'
)
Read more about Correlated subquery as well as Subqueries with EXISTS
SELECT TOP 1 1 FROM <table> will return you the first row with the value as 1 always, which you have defined as constant.
So if you change this to SELECT TOP 1 2 FROM <table> it will return the value as 2 always.
Difference between IN and EXISTS operators in SQL
Please read this:
http://awesomesql.wordpress.com/2009/07/31/difference-between-in-and-exists-operators-in-sql/