Using subquery at IN codition in Oracle Pivot - sql

If I don't know in advance what values are at colum name C0,
how to modify my IN condition?
If I use "IN ( 'a' AS A, 'b' AS B )", it works as below.
ROWNUM M A B
------ -- -- --
1 a__ 3.5 35
2 abd 1.5 15
3 abe 3.5 35
4 ace 5.5 55
But, If I use subquery "IN ( SELECT DISTINCT C FROM DATAA)",ORA-00936 error shows.
My code as below;
--Table and data
CREATE TABLE T4 (
C0 VARCHAR2(10),
C1 VARCHAR2(10),
C2 NUMBER
);
INSERT INTO T4 VALUES ('a','abd',1);
INSERT INTO T4 VALUES ('a','abd',2);
INSERT INTO T4 VALUES ('a','abe',3);
INSERT INTO T4 VALUES ('a','abe',4);
INSERT INTO T4 VALUES ('a','ace',5);
INSERT INTO T4 VALUES ('a','ace',6);
INSERT INTO T4 VALUES ('b','abd',10);
INSERT INTO T4 VALUES ('b','abd',20);
INSERT INTO T4 VALUES ('b','abe',30);
INSERT INTO T4 VALUES ('b','abe',40);
INSERT INTO T4 VALUES ('b','ace',50);
INSERT INTO T4 VALUES ('b','ace',60);
--Code
WITH DATAA AS (
SELECT ROWNUM,rr.C0,rr.M, rr.ss
FROM
(
SELECT C0,C1 M, AVG(C2) ss FROM T4 GROUP BY C0, C1
UNION
SELECT C0,SUBSTR(C1,1,1)||'__' ,AVG(C2) ss FROM T4 GROUP BY C0,SUBSTR(C1,1,1) ) rr
)
-- USING PIVOT
SELECT
ROWNUM,
TAB.*
FROM
(
SELECT
*
FROM
(
SELECT
M,
C0,
SS
FROM
DATAA
) PIVOT (
SUM ( SS )
FOR ( C0 )
IN ( 'a' AS A, 'b' AS B ) -- This condition works correctly, as expected
--IN ( SELECT DISTINCT C FROM DATAA) -- But,this subquery does not work. ORA-00936 error shows.
)
ORDER BY
1
) TAB;

You are searching for dynamic PIVOT. One way is to use PIVOT XML:
Adding the XML keyword to the PIVOT operator allows us to convert the generated pivot results to XML format. It also makes the PIVOT a little more flexible, allowing us to replace the hard coded IN clause with a subquery, or the ANY wildcard.
SELECT *
FROM (SELECT M, C0, SS FROM DATAA)
PIVOT XML (SUM(SS) FOR (C0) IN (SELECT DISTINCT C FROM DATAA))

Related

how to apply max clause on column other than group by columns in Hive

I have a hive table that contains data like below.
Table
---------------------
c1 c2 c3
a 1 7
a 2 6
a 3 3
a 3 1
a 3 2
I want to write a query to get value 2 from c3 column. The logic is, for column c1 select max(c2) and then within that max(c2) find max(c3)
I wrote query like
select c1, max(c3) from table1
group by c1
having c2=max(c2)
but this did not work as Hive says that I can use only those columns in having clause that are part of group by.
Please help me with this.
Note:- I need a single query for this. I am able to write the same in two queries
with your_data as (
select stack (5,
'a',1,7,
'a',2,6,
'a',3,3,
'a',3,1,
'a',3,2) as (c1,c2,c3)
)
select c1, max(c3) as max_c3
from
(
select c1,c2,c3,
rank() over(partition by c1 order by c2 desc) rn --max(c2) marked 1
from your_data
)s where rn=1 --filter records with max(c2)
group by c1
Result:
c1 max_c3
a 3
Using aggregate function:
create table val
(alpha varchar(10),id1 int,id2 int);
insert into val values ('a',3,3);
insert into val values ('a',3,1);
insert into val values ('a',3,2);
select alpha,id2 from
(
select alpha,max(id1) as id1,max(id2) as id2
from val group by alpha
)agg

How to add the sum of the 'sum of the two tables?'

I created Tables T1 and T2. I managed to add their sum, but I can't seem to add the sum of the T1 and T2 together (10+12 = 22) by adding a sum() in the beginning of the code.
CREATE TABLE T1(kW int)
CREATE TABLE T2(kW int)
SELECT T1C1, T2C1
FROM
( select SUM(Kw) T1C1 FROM T1 ) A
CROSS JOIN
( select SUM(Kw) T2C1 FROM T2 ) B
BEGIN
INSERT INTO T1 VALUES ('4');
INSERT INTO T1 VALUES ('1');
INSERT INTO T1 VALUES ('5');
INSERT INTO T2 VALUES ('7');
INSERT INTO T2 VALUES ('2');
INSERT INTO T2 VALUES ('3');
END
You should use union all to create a "virtual" column from the columns in the two tables:
SELECT SUM(kw)
FROM (SELECT kw FROM t1
UNION ALL
SELECT kw FROM t2) t
Try using a stored procedure. Doing so you will be able to store the sum of each table on a separated variable and then return the SUM of those two variables.
You can also make a UNION ALL and SUM the column you want. Notice that you should a UNION ALL to avoid eliminating duplicated values.
Another approach is to add the results of the two subqueries directly, using the built-in dummy table dual as the main driving table:
select ( select SUM(Kw) FROM T1 )
+ ( select SUM(Kw) FROM T2 ) as total
from dual;
TOTAL
----------
22

SQL Puzzle: How to generate row numbers ? (a classic puzzle with a cruel twist)

* A more refine version of this challenge can be found here.
The Puzzle
We got a table t:
create table t (i int not null);
The goal is to write, under the requirements specified below, a query that returns the same results as -
select t.i,row_number() over (order by t.i) as rn from t;
It might help you to know that there is another table in the database -
create table s (i int not null unique);
All I can tell you about table s, except for its definition, is that it has the same number of rows as table t, or maybe more.
Requirements
The solution should be a single SQL query (sub-queries are fine).
The use of any table other than t (and perhaps s), including table functions, is not allowed.
Only the following clauses are allowed: SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY and WITH (but not recursive!!).
The use of analytic functions is not allowed.
The use of rownum, rowid, guid and their like is not allowed.
The use of T-SQL, PL/SQL etc. is not allowed.
The use of UDF (User Defined Functions) is not allowed.
The use of variables is not allowed.
Data Sample
create table t (i int not null);
insert into t (i) values (1);
insert into t (i) values (2);
insert into t (i) values (3);
insert into t (i) values (3);
insert into t (i) values (4);
insert into t (i) values (5);
insert into t (i) values (5);
insert into t (i) values (5);
insert into t (i) values (6);
insert into t (i) values (7);
create table s (i int not null unique);
insert into s (i) values (3);
insert into s (i) values (12);
insert into s (i) values (13);
insert into s (i) values (28);
insert into s (i) values (41);
insert into s (i) values (52);
insert into s (i) values (56);
insert into s (i) values (57);
insert into s (i) values (83);
insert into s (i) values (91);
insert into s (i) values (97);
insert into s (i) values (99);
Requested result
I RN
---------- ----------
1 1
2 2
3 3
3 4
4 5
5 6
5 7
5 8
6 9
7 10
The following will work almost all the time:
with tt as (
select t.i, t.i + rand() as new_i
from t
)
select tt.i,
(select count(*)
from tt tt2
where tt2.new_i <= tt.new_i
) as rn
from tt;
Note: The function for rand() exists in all databases that support with, although the exact function (or combination) varies by database.
EDIT:
It is much more complicated to get something that works all the time. But:
with n as (
select (select count(*) from s s2 where s2.i <= s.i) as n
from s
),
tt as (
select i, count(*) as num
from t
group by i
),
ttt as
(select tt.*,
(select sum(num) from tt tt2 where tt2.i < tt.i
) as cume_num
from tt
)
select ttt.i, coalesce(cume_num, 0) + n.n
from ttt join
n
on n.n <= ttt.num;
I sort of like the first way better ;)
I would suggest this:
with
grp as
(select i,
count(*) cnt,
(select count(*) from t where i < t1.i) cntBefore
from t t1
group by i),
r as
(select (select count(*) from s where i <= s1.i) rn
from s s1)
select grp.i, r.rn
from r
inner join grp on r.rn between grp.cntBefore + 1 and grp.cntBefore + grp.cnt;
My variation:
with seq_num (i)
as
(
select (select count (*) as i from s s2 where s2.i <= s1.i)
from s s1
)
,t_with_seq (i,i_seq)
as
(
select t.i as i
,s.i as i_seq
from (select i
,count (*) as occurrences
from t
group by i
)
t
join seq_num s
on s.i <= t.occurrences
)
select ts1.i
,(select count (*) from t_with_seq ts2 where ts2.i < ts1.i or (ts2.i = ts1.i and ts2.i_seq <= ts1.i_seq)) as rn
from t_with_seq ts1
order by rn
;
with
num_gen as (
select (select count(*) from s where i <= s1.i) n
from s s1
),
groups as (
select i, count(*) as ct
from t
group by i
)
select g.i, ng.n + (select count(*) from t where t.i < g.i) rn
from num_gen ng inner join groups g on ng.n <= g.ct;
Note: Initially I offered a different solution, shown below for historical perspective (the first two comments refer to it). The OP is right, of course; I butchered a good idea. In the solution above I restored the idea to its proper simplicity.
-- OLD solution (replaced by the one above)
with
num_gen as (
select (select count(*) from s where i <= s1.i) n
from s s1
),
groups as (
select i, count(*) as ct
from t
group by i
),
new_numbers as (
select g.i i, g.i + power(10, -ng.n) new_i
from num_gen ng inner join groups g on ng.n <= g.ct
)
select nn.i, (select count(*) from new_numbers where new_i <= nn.new_i) rn
from new_numbers nn;

missing number or max number from the list

I am looking for missing number in the list, it works perfectly fine but when it start from 2, would it be possible to get 1. in below insertion
it should provide 1 not 4. please help thanks
drop table #temp
create table #temp
(
Number INT
)
insert into #temp
(Number)
select 2 union all
select 3 union all
select 5
SELECT MIN(t1.Number) + 1 AS MissingNumber
FROM #temp t1
LEFT OUTER JOIN #temp t2 ON (t1.Number + 1 = t2.Number)
WHERE t2.Number IS NULL
I will suggest you to create a separate numbers table to do this.
There a many ways to create number table. Check this link for more info
SELECT TOP (1000) n = Row_number()OVER (ORDER BY number)
INTO #numbers
FROM [master]..spt_values
ORDER BY n;
CREATE TABLE #temp
(Number INT)
INSERT INTO #temp(Number)
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 5
SELECT Min(t1.n) AS MissingNumber
FROM #numbers t1
LEFT OUTER JOIN #temp t2
ON ( t1.n = t2.Number )
WHERE t2.Number IS NULL
I think its not possible because join doesn't knows that number starts from 1. it will search for min value.
we can use while loop to solve problem
use this
IF OBJECT_ID('Tempdb..#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp ( Number INT )
INSERT INTO #temp
( Number )
VALUES ( 2 ),
( 3 ),
( 5 );
WITH cte
AS ( SELECT n = 1
UNION ALL
SELECT n + 1
FROM cte
WHERE n <= 100 --can be increased with OPTION ( MAXRECURSION {iteration value} ) at the end of the query
)
SELECT MIN(cte.n) AS MissingNumber
FROM cte
LEFT JOIN #temp t ON ( cte.n = t.Number )
WHERE t.Number IS NULL

recursion in sql server 2005

i Want to genrate possible combination with particluar no in sql server 2005 recursively.
e.g
we Have Main No 2 and Sub no 4,5,6
Combination are
2 4
2 5
2 6
4 5
4 6
5 6
5 2
...........like combination.
Thank u
declare #T table (Num int)
insert into #T values (2)
insert into #T values (4)
insert into #T values (5)
insert into #T values (6)
select
T1.Num as Num1,
T2.Num as Num2
from #T as T1
cross join #T as T2
Insert the numbers in TempTable and use Cross Join
Create Table #LeftTemp
( ID int,
)
Create Table #RightTemp
( ID int,
)
-- Write insert statements
Select * from #LeftTemp CROSS JOIN #RightTemp
;With
List AS (SELECT 2 AS y UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6)
SELECT
*
FROM
List CROSS JOIN list
You'd generate list from your tables