sql query on dual - sql

This:
select *
from dual
connect by level <= i
...will return result as
1
2
3
...
i
Can the query be modified to get result row wise? i.e
1 2 3 .....i

The functionality you're after is called "pivot"--it's converting row data into columnar data. The opposite is called "unpivot". There is PIVOT/UNPIVOT syntax, but it isn't available until Oracle 11g.
On Oracle 9i+, CASE statements are used while prior to that you need to use DECODE to construct the logic so the values come out in columns. Here's an example for addressing if the limit to LEVEL is five on Oracle 9i+:
SELECT MAX(CASE WHEN LEVEL = 1 THEN LEVEL END) AS one,
MAX(CASE WHEN LEVEL = 2 THEN LEVEL END) AS two,
MAX(CASE WHEN LEVEL = 3 THEN LEVEL END) AS three,
MAX(CASE WHEN LEVEL = 4 THEN LEVEL END) AS four,
MAX(CASE WHEN LEVEL = 5 THEN LEVEL END) AS five
FROM DUAL
CONNECT BY LEVEL <= 5
The aggregate function MAX is necessary to "flatten" the resultset into a single row/record.
If you got this far, you're thinking "but I don't want to have to specify for every column--I want it to be dynamic based on i...". There's two issues:
There is a limit to the number of columns - see ORA-01792 maximum number of columns in a table or view is 1000. That goes for 8i & 9i, anyways. And frankly, needing to generate that many columns raises serious questions about what you're trying to do with the resultset, if there might be a better approach...
Dynamic requirements means using dynamic SQL

Try this:
select trim(both ',' from sys_connect_by_path(level, ',')) as string
from dual
where level = 100
connect by level <= 100
update: Testing the output:
SQL>
SQL> select trim(both ',' from sys_connect_by_path(level, ',')) as string
2 from dual
3 where level = 20
4 connect by level <= 20
5 /
STRING
--------------------------------------------------------------------------------
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
another update: Guess I haven't read all comments well enough before posting, sorry. :) If you need to select each number as a separate column, then yes, see, OMG Ponies' answer - it's either pivot or dynamic SQL. :)

Related

Dual command in Big Query

"I am trying to achieve dual command in big query"
"I tried using the temp tables but not able to achieve it"
Oracle query: SELECT LEVEL - 1 F FROM
DUAL CONNECT BY LEVEL <= 2
"I expect the output in below format "
F
1
2
I have salary table with salaries : 50$ and 200$
I want to have duplicate of each row : 50$ ,-50$,200$ and -200$ is the output which i am expecting like 4 rows in total
You can use
SELECT
1
from (
select SESSION_USER())
to return a resultset with just one row.
Since BigQuery doesn't support CONNECT BY clause and since you want to get a positive and negative values from your data, you could try using a simple query like this one:
SELECT my_value FROM `project.dataset.table`
UNION ALL
SELECT -my_value FROM `project.dataset.table`
Notice the - in the second query as it'll give you negative values.
Hope it helps.

how connect by works to generate numbers

For the documentation, I know connect by can be used together with prior, in hierarchical queries. But quite often I see it is used to generate numbers:
SQL> select level from dual connect by level < 10;
LEVEL
----------
1
2
3
4
5
6
7
8
9
9 rows selected
SQL>
How it works here ? I mean how it generate 1, then 2, and so on. I can not see a hierarchy here, and connect by is not being used with prior. This has confused me for a long time.
The query does a linear recursive call.
Level is fake column generated by the recursion which tells the recursion depth of current iteration. The connect by clause does not need to refer to prior, it is condition just like any other which tells 'If this row has level smaller than 10, union it to the result set'

Oracle SQL connect by level

Can anyone explain the behavior of the below query:-
select level,t.*
from
( select 'one','two'from dual
union all
select 'one','two'from dual
) t
connect by level<=2
There are 2 rows in the inner query. I was expecting 4 rows of output, but i get 6 rows of output. Why is it so and how does this work?
The query starts with one of your two rows and adds both rows, then it continues with the second row and adds both rows again.
Change your query like this:
select level,t.*
from
( select 'one' from dual
union all
select 'two' from dual
) t
connect by level<=2;
This makes it easier to see what happens:
1 one
2 one
2 two
1 two
2 one
2 two
Read this http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm
When level <= 1, you will get each of the records 1 time.
When level <= 2, then you will get each level 1 time (for level 1) + the number of records in the table
(That means for this condition 2 records having level 1 + 2*2 records having level 2. This is the reason you are getting 6 records.)
CONNECT BY LEVEL gives following number of rows
x+x2+x3+x4+...x^n = Sx^n
where n is number of LEVEL and x is number of rows in a table

Make a query to split a line into x line depending on a field

I got a line in my data base, containing a fields with some names, separated by a ; .
I am trying to get, with a Select query, as many lines, that there is name in my field.
So, if I got in my DB :
id names
1 john;jack;mike
With this, i must get with this query :
SELECT id, split(names, ';') from table
1 john
1 jack
1 mike
I don't have any other table, so no join.
I write : split(names, ';'), but this is just an example of what I want to do.
But I don't know how to split my field names to do it like ahead.
I don't found any thing to help me, find a way to do it.
Do I need to use a function? Is there a function to do so with oracle?
Thank you.
SELECT id, TRIM(REGEXP_SUBSTR( names, '[^;]+', 1, LEVEL)) FROM table_name
CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(names, '[^;]+')) + 1
AND PRIOR id = id
AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL
SQL Fiddle

Calculating a field from SQL Query Selecting from multiple tables with Union

I have the following query, which works great. The problem I have is that in both tables (and the aggregate unioned table), there is a field called MTGUID. I need to multiply MTGUID by a number (let's say 1.35, for ease of use) and have it return that number in the MTGUID field. I have tried a dozen ways to do this and can't get anything to play ball. I can create a new column for each calculated price, like (BKRETAIL.MTGUID * 1.35) AS MTG1, but we've got tens of thousands of lines of code that specifically use MTGUID. Any ideas?
I'm using Firebird SQL.
SELECT * FROM (
SELECT BKRETAIL.* FROM BKRETAIL WHERE BKRETAIL.MKEY='SOMEKEY'
UNION SELECT BKWHOLESALE.* FROM BKWHOLESALE WHERE MKEY='SOMEKEY')
ORDER BY
case STATUS
WHEN 'RT' then 1
WHEN 'WH' then 2
WHEN 'OL' then 3
WHEN 'OD' then 4
WHEN NULL then 5
else 6
end;
How about this:
SELECT MTGUID * 1.35 as calculatedMTGUID, SUBSEL.* FROM (
SELECT BKRETAIL.* FROM BKRETAIL WHERE BKRETAIL.MKEY='SOMEKEY'
UNION SELECT BKWHOLESALE.* FROM BKWHOLESALE WHERE MKEY='SOMEKEY') SUBSEL
ORDER BY
case STATUS
WHEN 'RT' then 1
WHEN 'WH' then 2
WHEN 'OL' then 3
WHEN 'OD' then 4
WHEN NULL then 5
else 6
end;
try this
SELECT MTGUID * 1.35 AS MTGUID,<list rest OF COLUMNS here>
FROM (
SELECT BKRETAIL.* FROM BKRETAIL WHERE BKRETAIL.MKEY='SOMEKEY'
UNION SELECT BKWHOLESALE.* FROM BKWHOLESALE WHERE MKEY='SOMEKEY')
ORDER BY
case STATUS
WHEN 'RT' then 1
WHEN 'WH' then 2
WHEN 'OL' then 3
WHEN 'OD' then 4
WHEN NULL then 5
else 6
end;
One option would be to replace the original MTGUID column with computed one, ie
rename the original MTGUID column in table(s);
add new MTGUID column with desired expression using COMPUTED BY (expr);
Advantage of this is that you don't have to alter your SQL statements, disadvantage is that you have to maintain the expression in many places (all the tables which have the column). Of course, the queries which need the original MTGUID value must be updated to use the renamed column, but if the number of such statements is significantly lower it could be worth the trouble.
I think a better solution would be to "hide" all this stuff behind a view but this requires alerting your SQL queries...