How to create an ordered string from multiple columns? - sql

If I want to create an ordered string column (C4) given the columns C1, C2, and C3, how can I proceed so?

On on the assumption ssms indicates you're using SQL Server, you can unpivot your columns and use string_agg to concatenate them in order.
An example would be:
with data as (
select * from (values('Alton', 'Webs', 'James'), ('a', 'b', 'c'),('c', 'b', 'a')
)x(c1,c2,c3))
select *
from data
cross apply(
select String_Agg(c,'') within group(order by c) as c4
from(
values(c1),(c2),(c3)
)s(c)
)c4;

Related

Converting rows to columns without any calculation

I have a table with only a single column. How can I convert these rows to columns?
ColourCode
#FFCC00
#339966
#800080
#FF9900
The maximum possible number of rows will be 10.
I am expecting this:-
C1
C2
C3
C4
#FFCC00
#339966
#800080
#FF9900
I don't know how to dynamic generated column name, if you can combie sql script, you can use combined string to script to execute .
with code as (
select '#FFCC00' as ColourCode
union
select '#339966' as ColourCode
union
select '#800080' as ColourCode
union
select '#FF9900' as ColourCode )
select *
from
(select ColourCode ,
'C' + cast( ROW_NUMBER() OVER (Order by (select 1)) as nvarchar(max)) as rn -- generate sequence number
from code ) as sourcetable
PIVOT
(
max(ColourCode)
FOR rn IN ([C1],[C2],[C3],[C4]) -- predifned column Name, if you want to dynamic generated, you should use variable
) AS PivotTable;

Limited By Value Postgresql query

I have a couple of rows where values in one column are repeating and I need to get a couple of rows where every value is limited by const.
For example, i have this rows (1, 'a') (2, 'b') (3, 'a') (4,'c') (5, 'b') (6, 'a') and i limited every value in select by 2. Then I should not get a row with ID 6 cause this is an extra row cause I limited them by 2.
How I can do that?
thx for any help
If you have just two columns, say id and val, and you want just one row per value, then aggregation is enough:
select min(id) as id, val
from mytable
group by val
If there are more columns, you can use distinct on:
select distinct on (val) t.*
from mytable
order by val, id
Finally, if you want to be able to allow a variable number of rows per val, you can use window functions. Say you want 3 rows maximum per value:
select *
from (
select t.*, row_number() over(partition by val order by id) rn
from mytable t
) t
where rn <= 3

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

(Oracle) SQL: Column must contain a list of values

I'm trying to figure out an efficient (Oracle) SQL statement that verifies whether a column contains a specific list of values at least once.
One option would be to filter for that list, output all distinct values and then count them. So, something like this:
SELECT count(*)
FROM (
SELECT DISTINCT columnname
FROM table
WHERE columnname in ('a', 'b', 'c')
)
;
(And then check whether count(*) returns the number 3)
The problem with this is that the DISTINCT statement looks at the whole table, which is very bad performance-wise. All three values of my list could be at the very beginning, so i don't need to look at the millions of other rows. I only want to know that the column contains 'a', 'b' and 'c'.
Does anyone has an idea to solve this efficiently?
Thanks in advance!
It might be more efficient to look for each value individually:
select (case when exists (select 1 from t where col = 'a') and
exists (select 1 from t where col = 'b') and
exists (select 1 from t where col = 'c')
then 1 else 0
end) as has_all_three_flag
from dual;
This will be better particularly with an index on t(col).
If you wish to get rid of distinct, then try the below, Group by has better performance than distinct, See here.
SELECT count(*)
FROM (
SELECT columnname
FROM table
WHERE columnname in ('a', 'b', 'c')
GROUP BY columnname
)
;
Or you can avoid the usage of subquery by
SELECT count(DISTINCT columnname)
FROM table
WHERE columnname in ('a', 'b', 'c');

Oracle sql listagg based on another column

I am new to Oracle SQL and i need to deal with a task like below..
I have atttached an image here and what I needa do right now is, using SQL to show the result like right hand side from left hand side..
I need to listagg the Column 2 (C2) and Column 3 (C3), based on Column 1 (C1)
If C2 and C3 just got one record and no duplicated records,
then the result shows like the first row: 4316, Orange shipper 1, Hong Kong, China.
However there are some tricky cases like 4343/4403/4406 in C1.
C2 may have duplicated records but C3 doesnt have, vice versa.
I tried to use rank_over, then the result becomes the left hand side in the attached image.
SELECT t1.number AS C1,
t2.shipper AS C2,
rank() over (partition BY t2.shipper
ORDER BY t1.number) AS rank_over_c2,
t2.venue AS C3,
rank() over (partition BY t2.venue
ORDER BY t1.number) AS rank_over_c3
FROM table1 t1,
table2 t2
But after that I have no idea how i can get the result like the right hand side in the attached image..
Image is here:Left hand side is the original columns and data, I would like to get the result like the right hand side
Try:
SELECT * FROM
(
SELECT c1, listagg( c2, ', ' ) within group ( order by c2 ) as C2
FROM ( select distinct c1, c2 from c1c2 )
Group by c1
) x
JOIN (
SELECT c1, listagg( c3, ', ' ) within group ( order by c3 ) as C3
FROM ( select distinct c1, c3 from c1c2 )
Group by c1
) y
using( c1 )