Is there any way to select the greatest and second greatest numbers from multiple columns?
Example:
Col1 = 0;
Col2 = 4;
Col3 = 6;
Col4 = 3;
My greatest would be 6 followed by a second greatest of 4.
I'm trying implement something like this:
SELECT GREATEST(Col1, Col2, Col3, Col4) AS High,
GREATEST(Col1, Col2, Col3, Col4) AS Low
WHERE Low < High FROM tbl;
For 4 columns you can do it like this:
select
greatest(col1, col2, col3, col4) high,
greatest(col1, col2, col3) +
greatest(col1, col2, col4) +
greatest(col1, col3, col4) +
greatest(col2, col3, col4) -
3 * greatest(col1, col2, col3, col4) low
from tablename
You add all the greatest of all the combinations of 3 columns and subtract the greatest of all multiplied by 3 because out of the 4 combinations the 3 will result to the greatest of all.
See the demo.
Results:
| high | low |
| ---- | --- |
| 6 | 4 |
Forpas solution is clever, but it doesn't work with non-numeric data. A more conventional solution works when the values are different and not null:
select greatest(a, b, c, d),
(case greatest(a, b, c, d)
when a then greatest(b, c, d)
when b then greatest(a, c, d)
when c then greatest(a, b, d)
else d
end)
from t;
Related
I have one table with these value
col1 col2 col3
---------------------- ------------------- -------------------------
1 0 ADD SERVICE ACTIVITY 1
0 1 ADD SERVICE ACTIVITY 1
0 8 Docment testing 2 (C07)
I want result like:
col1 col2 col3
---------------------- ------------------- -------------------------
1 1 ADD SERVICE ACTIVITY 1
0 8 Docment testing 2 (C07)
It seems that you want to group your data by column col3. I'm not sure whether results for col1 and col2 are sums or max values.
--for MAX:
SELECT MAX(COL1) as col1, MAX(COL2) as col2, COL3
/*-- for SUM:
SELECT SUM(COL1) as col1, SUM(COL2) as col2, COL3
*/
FROM test
GROUP BY COL3;
I have a database with rows and columns of data, the row,col data is some summed data (ie. 1 3 5 7 from original data = 1 2 2 2).
I want to get the original data by subtraction eg. val=r1c2-r1c1 etc across the rows and columns. Is this possible in sql without having to do lots of individual select statements for each row/column?
I would like to do this for all rows and columns in database, like the following pseudocode
a[ 1,3,5,7;
2,5,6,7 ];
for(i=0;i<size(a,1); i++)
for(j=0;j<size(a,2)-1; j++)
b(i,j)=a(i,j+1)-a(i,j);
Try this.
SELECT col1,
col2 - col1 col2,
col3 - col2 col3,
col4 - col3 col4
FROM (SELECT 1 col1,
3 col2,
5 col3,
7 col4) a
Update: Same query will work for more than one row
SELECT col1,
col2 - col1 col2,
col3 - col2 col3,
col4 - col3 col4
FROM (SELECT 1 col1,3 col2,5 col3,7 col4
UNION ALL
SELECT 1 col1,3 col2,9 col3,11 col4
UNION ALL
SELECT 1 col1,3 col2,5 col3,7 col4) a
i have a denormalized table, where i have to count the number of same values in other columns.
I'm using the InfiniDB Mysql Storage Engine.
This is my Table:
col1 | col2 | col3
------------------
A | B | B
A | B | C
A | A | A
This is what i expect:
col1Values | col2Values | col3Values
------------------------------------
1 | 2 | 2 -- Because B is in Col2 and Col3
1 | 1 | 1
3 | 3 | 3
Is there something like
-- function count_values(needle, haystack1, ...haystackN)
select count_values(col1, col1, col2, col3) as col1values -- col1 is needle
, count_values(col2, col1, col2, col3) as col2values -- col2 is needle
, count_values(col3, col1, col2, col3) as col3values -- col3 is needle
from table
or am i missing something simple that will do the trick? :-)
Thanks in advance
Roman
select
CASE WHEN col1 = col2 and col1=col3 THEN '3'
WHEN col1 = col2 or col1=col3 THEN '2'
WHEN col1 != col2 and col1!=col3 THEN '1'
ELSE '0' END AS col1_values,
CASE WHEN col2 = col1 and col2=col3 THEN '3'
WHEN col2 = col1 or col2=col3 THEN '2'
WHEN col2 != col1 and col2!=col3 THEN '1'
ELSE '0' END AS col2_values,
CASE WHEN col3 = col1 and col3=col2 THEN '3'
WHEN col3 = col1 or col3=col2 THEN '2'
WHEN col3 != col1 and col3!=col2 THEN '1'
ELSE '0' END AS col3_values
FROM table_name
fiddle demo
Assuming the table has got a key, you could:
Unpivot the table.
Join the unpivoted dataset back to the original.
For every column in the original, count matches against the unpivoted column.
Here's how the above could be implemented:
SELECT
COUNT(t.col1 = s.col OR NULL) AS col1Values,
COUNT(t.col2 = s.col OR NULL) AS col2Values,
COUNT(t.col3 = s.col OR NULL) AS col3Values
FROM atable t
INNER JOIN (
SELECT
t.id,
CASE colind
WHEN 1 THEN t.col1
WHEN 2 THEN t.col2
WHEN 3 THEN t.col3
END AS col
FROM atable t
CROSS JOIN (SELECT 1 AS colind UNION ALL SELECT 2 UNION ALL SELECT 3) x
) s ON t.id = s.id
GROUP BY t.id
;
The subquery uses a cross join to unpivot the table. The id column is a key column. The OR NULL bit is explained in this answer.
I have found a different, very very simple solution :-)
select if(col1=col1,1,0) + if(col2=col1,1,0) + if(col3=col1,1,0) as col1values -- col1 is needle
from table
In Mysql i have the fdllowing query along with the results below
drop table tab1;
CREATE TEMPORARY TABLE tab1
(col1 integer,col2 integer(10),col3 varchar(10),col4 integer)engine=memory
insert into tab1
values(100,1,'Hello',9);
insert into tab1
values(200,1,'HelloWrld',8);
insert into tab1
values(300,1,'HelloTher',7);
insert into tab1
values(400,2,'HiThere',6);
insert into tab1
values(500,3,'Howdy',5);
insert into tab1
values(600,3,'Hiya',4);
select col1,col2,col3,col4,min(col4)
from tab1
group by col2
'100', '1', 'Hello', '9', '7'
'400', '2', 'HiThere', '6', '6'
'500', '3', 'Howdy', '5', '4'
In Oracle i want the same result as Mysql
with tab1 as (
select 100 col1, 1 col2, 'Hello' col3,9 col4 from dual
union all
select 200 col1, 1 col2, 'HelloWrld' col3,8 col4 from dual
union all
select 300 col1, 1 col2, 'HelloTher' col3,7 col4 from dual
union all
select 400 col1, 2 col2, 'HiThere' col3,6 col4 from dual
union all
select 500 col1, 3 col2, 'Howdy' col3,5 col4 from dual
union all
select 600 col1, 3 col2, 'Hiya' col3,4 col4 from dual
)
select min(col1),col2,min(col3),col4,min(col4)
from tab1
group by col2,col4
Result I get is this
MIN(COL1) COL2 MIN(COL3) COL4 MIN(COL4)
---------- ---------- --------- ---------- ----------
100 1 Hello 9 9
200 1 HelloWrld 8 8
500 3 Howdy 5 5
600 3 Hiya 4 4
300 1 HelloTher 7 7
400 2 HiThere 6 6
What i would like to have is this
'100', '1', 'Hello', '9', '7'
'400', '2', 'HiThere', '6', '6'
'500', '3', 'Howdy', '5', '4'
How do i achieve Mysql like group by in Oracle
I am unable to get this and this is part of a long query that i am trying to resolve
According to the mysql documentation, the results for columns not specified in the group by can come from any rows.
So, a perfectly reasonable query in Oracle is:
select min(col1),col2,min(col3),min(col4),min(col4)
from tab1
group by col2
If your mysql code was depending on a particular value being chosen, then that code is broken. You will need to figure out exactly what you want, and figure out how to get that in Oracle.
Assuming that your intention is to get a deterministic result (unlike the MySQL result which is not deterministic) and that the col1 - col4 data you want to retain is the data for the row with the smallest col1 value for a given col2 value, you can use analytic functions
SQL> ed
Wrote file afiedt.buf
1 with tab1 as (
2 select 100 col1, 1 col2, 'Hello' col3,9 col4 from dual
3 union all
4 select 200 col1, 1 col2, 'HelloWrld' col3,8 col4 from dual
5 union all
6 select 300 col1, 1 col2, 'HelloTher' col3,7 col4 from dual
7 union all
8 select 400 col1, 2 col2, 'HiThere' col3,6 col4 from dual
9 union all
10 select 500 col1, 3 col2, 'Howdy' col3,5 col4 from dual
11 union all
12 select 600 col1, 3 col2, 'Hiya' col3,4 col4 from dual
13 )
14 select col1,
15 col2,
16 col3,
17 col4,
18 min_col4
19 from (select col1,
20 col2,
21 col3,
22 col4,
23 min(col4) over (partition by col2) min_col4,
24 rank() over (partition by col2 order by col1) rnk
25 from tab1)
26* where rnk = 1
SQL> /
COL1 COL2 COL3 COL4 MIN_COL4
---------- ---------- --------- ---------- ----------
100 1 Hello 9 7
400 2 HiThere 6 6
500 3 Howdy 5 4
When you use Group By how do you keep the other fields in sync when using aggregates
Here I am trying to find the min value of col4 when col2 = xxx
select col1, col2, col3, min(col4)
from table
where col2 = 'xxx'
group by col3
I can get the minimum value in col4 but col1 is not correct but col2, col3, col4 are.
Can anyone show me how to do this ?
Thanks
You are using non-standard MySQL extension to GROUP BY.
This query in fact reads as "for each distinct value of col3, select the minimal value of col4 along with the values of col1 and col2 from a single row of table having this value of col3 in no particular order"
Like, if we have the following data:
col1 col2 col3 col4
---- --- --- ----
A A 1 1
B B 1 2
C C 2 3
D D 2 4
, this query:
SELECT col1, col2, col3, MIN(col4)
FROM mytable
GROUP BY
col3
will return either of the following:
col1 col2 col3 col4
---- --- --- ----
A A 1 1
C C 2 3
col1 col2 col3 col4
---- --- --- ----
B B 1 1
C C 2 3
col1 col2 col3 col4
---- --- --- ----
A A 1 1
D D 2 3
col1 col2 col3 col4
---- --- --- ----
B B 1 1
D D 2 3
i. e. it can return any value of col1 and col2 found in the rows that contribute to the corresponding group.
This is equivalent of FIRST_VALUE analytic function, but in no particular order.
Update:
To select values of col1 and col2 corresponding to the minimal value of col4 within each group, use this:
SELECT col1, co2, col3, col4
FROM (
SELECT col1, col2, col3, col4,
COALESCE(#col3 = col3, FALSE) AS grp,
#col3 := col3 AS nv
FROM (
SELECT #col3 := NULL
) vars, table
WHERE col2 = 'xxx'
ORDER BY
col3, col4
) q
WHERE NOT grp
select a.col3, a.col2, a.col1, a.col4
from table as a natural join
(select col3, min(col4) as col4 from table
where col2='xxx'
group by col3 ) as b
where a.col2 = 'xxx' -- sometimes this helps the optimizer even though it's redundant
you can get into a bit of trouble here when there may be multiple rows with the same col3, col4, and col2, but different col1s -- pretty straightforward to fix with rownums and such, but that gets db-specific.
I guess you want the col1-3 corresponding to the min(col4) for each
col3?
Something like:
select X.col1, X.col2, X.col3, X.col4 from table X
join (select col3, min(col4) as mcol4 from table where col2='xxx' group by col3) as Y
on X.col3=Y.col3 and X.col4=Y.mcol4
where X.col2='xxx';