Alternate method for PIVOT - IN with sub-query support - oracle

As per oracle documentation, PIVOT function doesn't support sub-query in the "IN" clause but it is possible in the PIVOT XML function.
E.g.
SELECT *
FROM table_name
PIVOT
(
SUM(column_name_1)
FOR [column_name_2] IN (['Output_Column1'],['Output_Column2'])
)
AS aliasName
I need to replace the ['Output_Column1'],['Output_Column2'] with sub-query.
Is there some other function equivalent to PIVOT where we can supply sub-query instead hard coding the entire output columns or even in the PIVOT function itself?.

No, the number of columns must be known at parse time. For PIVOT XML there is no problem because such query returns only one column.

Related

How to use a query result or column value to define a select column name?

How can I use a column value as a column name. I've tried this:
SELECT TableX.(
SELECT OdTable.columnamecell
from OdTable
where 1 =1
AND OdTable.KeyValue = TableX.SomeValue
) as MyValue
,TableX.OtherValue as OtherValue
, TableX.SomeValue
from TableX
WHERE 1 = 1
Or to say it another way: Can I use a table column value as a column name for another query or sub-query?
To clarify: The table: OdTable has a column with values that are the column name in another table.
No, and Yes. You can't do this with "standard" SQL; all table and column names must be known, as literals, when the query is compiled; they can't be provided at runtime. What you want is called "dynamic SQL"; sometimes it is the only solution to a problem, but most of the time it is used when it is not necessary. It has several disadvantages (security risk, performance penalty, difficulty to maintain, ...)

optimize query with minus oracle

Wanted to optimize a query with the minus that it takes too much time ... if they can give thanked help.
I have two tables A and B,
Table A: ID, value
Table B: ID
I want all of Table A records that are not in Table B. Showing the value.
For it was something like:
Select ID, value
FROM A
WHERE value> 70
MINUS
Select ID
FROM B;
Only this query is taking too long ... any tips how best this simple query?
Thank you for attention
Are ID and Value indexed?
The performance of Minus and Not Exists depend:
It really depends on a bunch of factors.
A MINUS will do a full table scan on both tables unless there is some
criteria in the where clause of both queries that allows an index
range scan. A MINUS also requires that both queries have the same
number of columns, and that each column has the same data type as the
corresponding column in the other query (or one convertible to the
same type). A MINUS will return all rows from the first query where
there is not an exact match column for column with the second query. A
MINUS also requires an implicit sort of both queries
NOT EXISTS will read the sub-query once for each row in the outer
query. If the correlation field (you are running a correlated
sub-query?) is an indexed field, then only an index scan is done.
The choice of which construct to use depends on the type of data you
want to return, and also the relative sizes of the two tables/queries.
If the outer table is small relative to the inner one, and the inner
table is indexed (preferrable a unique index but not required) on the
correlation field, then NOT EXISTS will probably be faster since the
index lookup will be pretty fast, and only executed a relatively few
times. If both tables a roughly the same size, then MINUS might be
faster, particularly if you can live with only seeing fields that you
are comparing on.
Minus operator versus 'not exists' for faster SQL query - Oracle Community Forums
You could use NOT EXISTS like so:
SELECT a.ID, a.Value
From a
where a.value > 70
and not exists(
Select b.ID
From B
Where b.ID = a.ID)
EDIT: I've produced some dummy data and two datasets for testing to prove the performance increases of indexing. Note: I did this in MySQL since I don't have Oracle on my Macbook.
Table A has 2600 records with 2 columns: ID, val.
ID is an autoincrement integer
Val varchar(255)
Table b has one column, but more records than Table A. Autoincrement (in gaps of 3)
You can reproduce this if you wish: Pastebin - SQL Dummy Data
Here is the query I will be using:
select a.id, a.val from tablea a
where length(a.val) > 3
and not exists(
select b.id from tableb b where b.id = a.id
);
Without Indexes, the runtime is 986ms with 1685 rows.
Now we add the indexes:
ALTER TABLE `tablea` ADD INDEX `id` (`id`);
ALTER TABLE `tableb` ADD INDEX `id` (`id`);
With Indexes, the runtime is 14ms with 1685 rows. That's 1.42% the time it took without indexes!

Can i use the column in order by clasue

I have specifiec requirement .Actually this is my query. here amount is a column in my table.but i did not mention the amount column in select statement.here can i use this column in oreder by clause.
SELECT stud_name, stud_roll, stud_prg
FROM programcl
ORDER BY 3, amount, 1;
Yes, you can mix both positional and named assignments in your ORDER BY clause.
The positional assignments must appear in your SELECT list. The named assignments do not have to.
can i use this column in oreder by clause.
Yes of course you can use a different column in order by clause that wasn't selected from your select statement.
For example
select col1 from tab1
order by col2;
by this way you get results from col1 which will be displayed on order of col2.
Its Worth trying

Oracle - Look up for the data in pivoted table

I have a table which has columns as follows:
USERID, USERTYPE, DIVISION, SUBDIVISION
For each userid, there will be one or more usertypes (e.g. a user can be a developer or administrator or both). Depending on the usertype a user can be subscribed to the divisions and optionally its subdivisions.
USERID, USERTYPE and DIVISION are not null columns.
The output is required in the following format -
USERID, USERTYPE, DIVISION1, DIVISION2, DIVISION3 .. and so on
So, there should be a unique record for a combination of USERID-USERTYPE.
For this I have used PIVOT operator which works fine. I have also created a temporary table (let's say Table1) to store this result of this query.
Now, if a user is subscribed to subdivisions, the values of subdivisions should be written under that division as comma separated values. If it is not subscribed to subdivisions, simple divisions will appear under its respective column.
I have written a query using LISTAGG function which gives me comma separated subdivisions for each USERID-USERTYPE combination. The result of this query is stored in Table2.
Now when I join the tables Table1 and Table2 on USERID and USERTYPE, I get multiple rows for a single USERID-USERTYPE combination, which is obvious but not what is needed.
Here is some sample data:
Please note the records for USERID = 3.
What I am getting is in "Result of join query" and what I need is in "Final Result".
Also, I cannot use LISTAGG before the pivot query, because later on while building the pivot query it will be too tedious to list all the possible combinations of subdivisions.
I am sure I am missing some small point here, but cannot figure out what.
Any suggestions or pointers will be of great help.
Thanks in advance.
There are no need to list all subdivisions in pivot query, just aggregate it within a groups of unique combinations of USERID, USERTYPE, DIVISION and use nvl(AGGREGATED_VALUE,DIVISION) to get a value for filling pivot table.
If source_table is a table with USERID, USERTYPE, DIVISION, SUBDIVISION columns which you mentioned first in your question, then this example must work for you:
select * from (
select
userid,
usertype,
division,
-- get prepared value for pivot
nvl(
listagg(subdivision, ',') within group (order by subdivision),
division
) subdiv_list
from
source_table
group by
userid, usertype, division
)
pivot (
max(subdiv_list) for division in ('Div1', 'Div2')
)
SQLFidlle
P.S. Just as a side story, generation of a list of columns dynamically may be useful. Check this SO article.

SQL Server 2008 search for date

I need to search rows entered on a specific date.
However the datatype of column I need to search on is datetime, and the datatype of argument is Date.
I can use the the query like
Select result
from table
where
convert(date, Mycolumn) = #selectedDate
but this would affect the SARGability of the query and will not use indexes created on mycolumn.
I was trying to use the following query:
Select result
from table
where
Mycolumn
BETWEEN #selectedDate AND Dateadd(s, -1, Dateadd(D, 1, #selectedDate))
However this does not work since the #selectedDate is Date type and a second can't be added or removed.
Can someone help me with a working query?
Thanks.
It is my understanding that using:
convert(date, Mycolumn) = #selectedDate
is SARGable. It will use the index on Mycolumn (if one exists). This can easily be confirmed by using the execution plan.
Select result
from table
where
Mycolumn >= #selectedDate
AND Mycolumn < Dateadd(D, 1, #selectedDate)
If you need to do these searches a lot, you could add a computed, persisted column that does the conversion to DATE, put an index on it and then search on that column
ALTER TABLE dbo.YourTable
ADD DateOnly AS CAST(MyColumn AS DATE) PERSISTED
Since it's persisted, it's (re-)calculated only when the MyColumn value changes, e.g. it's not a "hidden" call to a stored function. Since it's persisted, it can also be indexed and used just like any other regular column:
CREATE NONCLUSTERED INDEX IX01_YourTable_DateOnly ON dbo.YourTable(DateOnly)
and then do:
SELECT result FROM dbo.YourTable WHERE DateOnly = #SelectedDate
Since that additional info is stored in the table, you'll be using a bit more storage - so you're doing the classic "space vs. speed" trade-off; you need a bit more space, but you get more speed out of it.

Resources