I have a table created in Materialized view from 10 different tables.
Part of it looks like this
group_name
value1
value2
group1
100
20
group2
200
40
unknown
300
60
TOTAL
600
120
I have to rearrange all values from rows with value group_name = 'unknown' to other rows. The final table should look like this
group_name
value1
value2
group1
200
40
group2
400
80
TOTAL
600
120
So formula for 'group1' would be:
unknown x group1 x (TOTAL-unknown) + group1
The table is created with massive code and please note - I didn't write it, it was given to me and I have to work with it. I don't like how it looks, so please spare your anger. Anyway, the query looks like this:
TABLESPACE pg_default
AS
WITH table_value1 AS (
SELECT
table1.group_name,
table1.value1,
FROM table1
), table_value2 AS (
SELECT
table2.group_name,
table2.value2,
FROM table2
), TOTAL_groups AS (
SELECT
'value1'::text AS group_name,
sum(xy_table."value1")::numeric as results
FROM xy_table
UNION ALL
SELECT
'value2'::text AS group_name,
sum(xy_table."value2")::numeric as results
FROM xy_table
UNION ALL
SELECT
'unknown'::text AS group_name,
sum(xy_table."unknown")::numeric as results
FROM xy_table
), TOTAL AS (
SELECT
TOTAL_groups.group_name,
TOTAL_groups.results
FROM TOTAL_groups
UNION ALL
'TOTAL'::text AS group_name,
round(sum(TOTAL_groups.raba), 1) as results
FROM skupaj_energenti
)
SELECT
a.group_name,
COALESCE(a.results, 0::numeric) AS value1,
COALESCE(a.results, 0::numeric) AS value2
FROM table_value1 a
LEFT JOIN table_value2 b ON b.group_name = a.group_name
LEFT JOIN TOTAL c ON f.group_name = a.group_name
WITH DATA;
I have no idea how should I write such conditions in SQL. Please help.
Distribute 'unknown' row to other rows. Assuming value1, value2 are DECIMAL
select group_name, value1 * (1 + k1) value1, value2 * (1 + k2) value2
from tbl
cross join (
select sum(case group_name when 'unknown' then value1 end) / sum(case group_name when 'TOTAL' then value1 else -value1 end) k1,
sum(case group_name when 'unknown' then value2 end) / sum(case group_name when 'TOTAL' then value2 else -value2 end) k2
from tbl
where group_name in ('TOTAL', 'unknown')
) t
where tbl.group_name not in ('TOTAL', 'unknown')
db<>fiddle
Related
I have a RELATION table
NUM1 | NUM2 | NUM3
-- --- -----
1 2 3
2 4 5
3 4 null
3 4 null
and the actual INFO table where NUM is primary key.
NUM | A_LOT_OF_OTHER_INFO
--- --------------------
1 asdff
2 werwr
3 erert
4 ghfgh
5 cvbcb
I want to create a view to see the count of the NUM that appeared in any of the NUM1, NUM2, NUM3 of the RELATION table.
MY_VIEW
NUM | A_LOT_OF_OTHER_INFO | TOTAL_COUNT
--- -------------------- ------------
1 asdff 1
2 werwr 2
3 erert 3
4 ghfgh 3
5 cvbcb 1
I can do this by doing three selects from RELATION table and UNION them, but I do not want to use UNION because the tables have a lot of records, MY_VIEW is already large enough and I am looking for a better way to join to the RELATION table in the view. Can you suggest a way?
What i would try is to unpivot the relation table.
After that join the info table on the values and count the number of times the val gets repeated.
create table relation(num1 int,num2 int, num3 int);
insert into relation values(1,2,3);
insert into relation values(2,4,5);
insert into relation values(3,4,null);
create table info(num int, a_lot_of_other_info varchar2(100));
insert into info
select 1,'asdff' from dual union all
select 2,'werwr' from dual union all
select 3,'erert' from dual union all
select 4,'ghfgh' from dual union all
select 5,'cvbcb' from dual
select a.num
,max(a_lot_of_other_info) as a_lot_of_other_info
,count(*) as num_of_times
from info a
join (select val
from relation a
unpivot(val for x in (num1,num2,num3))
)b
on a.num=b.val
group by a.num
order by 1
I would suggest a correlated subquery:
select i.*,
(select ((case when r.num1 = i.num then 1 else 0 end) +
(case when r.num2 = i.num then 1 else 0 end) +
(case when r.num3 = i.num then 1 else 0 end)
)
from relation r
where i.num in (r.num1, r.num2, r.num3)
) as total_count
from info i;
If performance is a consideration, it might be faster to use left joins:
select i.*,
((case when r1.num1 is not null then 1 else 0 end) +
(case when r2.num1 is not null then 1 else 0 end) +
(case when r3.num1 is not null then 1 else 0 end)
) as total_count
from info i left join
relation r1
on i.num = r1.num1 left join
relation r2
on i.num = r2.num2 left join
relation r3
on i.num = r3.num3;
In particular, this will make optimal use of three separate indexes on relation: relation(num1), relation(num2), and relation(num3).
It seems what you want is UNPIVOT. Perhaps easiest to do with a cross join in this case:
select NUM, count(*) as TOTAL_COUNT
from (
select decode(column_value, 1, NUM1, 2, NUM2, 3, NUM3) as NUM
from RELATION cross join table(sys.odcinumberlist(1,2,3))
)
group by NUM
;
Then join this to the second table; the join part is really irrelevant here.
Given an SQL table like this
id value1 value2
---------------
1 1 1
2 1 1
3 1 1
4 2 1
5 2 2
6 3 1
I want to find all the value1's that have duplicate value1 (i.e using group by having count(*)>1) but only if they have different values for value2
So in this example I just want to return 2
Im using Postgres
If I understand correctly, this is group by with a having clause:
select value1
from t
group by value1
having min(value2) <> max(value2)
use
select * from ( select * , ROW_NUMBER() OVER(PARTITION BY Value1 ORDER BY Value1 , Value2 ASC) AS RowValue1, ROW_NUMBER() OVER(PARTITION BY Value1 , Value2 ORDER BY Value1 , Value2 ASC) AS RowValue2 from Table_1 ) As TableTmp where TableTmp.RowValue1 <> TableTmp.RowValue2
Or
select * from Table_1 where value1 in (select value1 from Table_1 group by value1 having min(value2) <> max(value2) )
I have data like this:
ID Result
1 value1
2 value1
2 value2
3 value1
4 value1
4 value2
4 value3
How can I accomplish in teradata SQL the pivot table like in Excel.
ID Value1 Value2 ...
1 count of Value1 for ID 1 count of Value2 for ID 1 ...
2 count of Value1 for ID 2 count of Value2 for ID 1 ...
3 ... ... ...
assuming that there is a large number of ID and varying number of Values.
SELECT sum(case when Result='Value1' then ID end) "Value1"
, sum(case when Result='Value2' then ID end) "Value2"
FROM your_table
GROUP BY null;
Not much context can be added here I'm afraid, except this is the way pivots can be implemented in TD up to v15.x
So i found the answer and i would like to share it with you
First of all you need to recalculate the data to know the counts for id||Value
CREATE TABLE myTable_count as (
SELECT ID, Result, count(1) as countOfResult
FROM myTable
group by ID, Result
) WITH DATA
Then you can do a pivot, but you have to know the names of result's
SELECT ID,
sum(CASE WHEN Result='Value1' then countOfResult else NULL END) Value1,
sum(CASE WHEN Result='Value2' then countOfResult else NULL END) Value2
FROM myTable_count
GROUP BY ID;
If it help you give it a vote up.
SELECT
id,
count(
CASE WHEN result1 = 'value1' THEN id END
) AS value1,
COUNT(
CASE WHEN result1 = 'value2' THEN id END
) AS value2,
COUNT(
CASE WHEN result1 = 'value3' THEN id END
) as value3
FROM
pivot_tb1
group by
1;
Suppose there is data like below:
ID Name Cost
ID1 A 10
ID1 A 60
ID1 B 20
ID1 C 20
ID2 B 10
ID2 B 50
ID2 C 50
ID3 B 5
Here in the table above, ID and NAME are not unique.
And I want to get SUM values based on NAME, so the expected result is like below:
ID A_Costs B_Costs C_Costs AB_Costs
ID1 70 20 20 90
ID2 60 50 60
ID3 5 5
A_Cost, B_Costs, and C_Costs are costs when the name is A, B or C.
But what do I do if I want to get costs when the name is A and B?
So what I was trying to do was this:
Select t2.ID,
SUM(DECODE (t2.name, 'A', t2.Cost, null)),
SUM(DECODE (t2.name, 'B', t2.Cost, null))
--(select sum(t1.cost) from table t1. where t1.name in ('A','B') and t1.id = t2.id)
from table t2
group by t2.id
But this does not work.
How do I get the costs when the name is A and B like the line I commented out? Is there any effective way to get the value like that in one query?
Thank you in advance.
If you want to use decode(), you can do:
sum(decode(t2.name, 'A', t2.cost, 'B' t2.cost))
Or you can use a case statement:
sum(case when t2.name in ('A', 'B') then t2.cost end)
Full query:
select id,
sum(case when name = 'A' then cost end) as a_costs,
sum(case when name = 'B' then cost end) as b_costs,
sum(case when name = 'C' then cost end) as c_costs,
sum(case when name IN ('A', 'B') then cost end) as ab_costs
from SomeTable
group by id
order by id
SQL Fiddle Demo
You will also have to aggregate after using sum in the inner query.
select
id, max(a_cost) as A_Costs, max(b_cost) as B_Costs,
max(c_cost) as C_Costs, nvl(max(a_cost),0) + nvl(max(b_cost),0) as AB_Costs
from (
select ID,
sum(case when name = 'A' then cost end) as a_cost,
sum(case when name = 'B' then cost end) as b_cost,
sum(case when name = 'C' then cost end) as c_cost
from table
group by id
) t
group by id
I have a table, sort of like this:
Items
-----------
ID Value1 Value2 Value3 Value4 Value5 Value6
1 345895 435234 342534 678767 5455 423555
2 3245 549238 230944 923948 234488 234997
3 490458 49349 234234 87810 903481 3940102
4 849545 435234 67678 98741 99084 978897
How would I write a query, that finds all the items, that have at least 3 values (just an example, could be more than 3) in common with a specific item i.e. I have an item
345895 435234 67678 98741 5455 423555
and running this query would give me
1 345895 435234 342534 678767 5455 423555
4 849545 435234 67678 98741 99084 978897
Any help would be greatly appreciated. Thank you.
You can use CASE statements in the WHERE clause in order to calculate the number of matches:
SELECT i.*
FROM Items AS i
CROSS JOIN ( VALUES ( 345895, 435234, 67678, 98741, 5455, 423555) ) AS Item(v1, v2, v3, v4, v5, v6)
WHERE (CASE WHEN i.Value1 = Item.v1 THEN 1 ELSE 0 END) +
(CASE WHEN i.Value2 = Item.v2 THEN 1 ELSE 0 END) +
(CASE WHEN i.Value3 = Item.v3 THEN 1 ELSE 0 END) +
(CASE WHEN i.Value4 = Item.v4 THEN 1 ELSE 0 END) +
(CASE WHEN i.Value5 = Item.v5 THEN 1 ELSE 0 END) +
(CASE WHEN i.Value6 = Item.v6 THEN 1 ELSE 0 END) >= 3
This is one way:
; with sub as(
select 345895 as mynum
union all select 435234
union all select 67678
union all select 98741
union all select 5455
union all select 423555
)
select i.*
from items i
join
(
select x.id
from(
select id, value1 as val from items union all
select id, value2 from items union all
select id, value3 from items union all
select id, value4 from items union all
select id, value5 from items union all
select id, value6 from items
) x join sub s on x.val = s.mynum
group by x.id
having count(*) >= 3
) x on x.id = i.id
Fiddle: http://sqlfiddle.com/#!6/1dff3/2/0