I have a table of two columns
Col1 Col2
A 1
A 2
A 3
B 1
B 2
B 3
Output I need is like this
Col1 Col2
A 1
A 1,2
A 1,2,3
B 1
B 1,2
B 1,2,3
Thank you in advance.
Here is a solution which would work for MySQL. It uses a correlated subquery in the select clause to group concatenate together Col2 values. The logic is that we only aggregate values which are less than or equal to the current row, for a given group of records sharing the same Col1 value.
SELECT
Col1,
(SELECT GROUP_CONCAT(t2.Col2 ORDER BY t2.Col2) FROM yourTable t2
WHERE t2.Col2 <= t1.Col2 AND t1.Col1 = t2.Col1) Col2
FROM yourTable t1
ORDER BY
t1.Col1,
t1.Col2;
Demo
Here is the same query in Oracle:
SELECT
Col1,
(SELECT LISTAGG(t2.Col2, ',') WITHIN GROUP (ORDER BY t2.Col2) FROM yourTable t2
WHERE t2.Col2 <= t1.Col2 AND t1.Col1 = t2.Col1) Col2
FROM yourTable t1
ORDER BY
t1.Col1,
t1.Col2;
Demo
Note that the only real change is substituting LISTAGG for GROUP_CONCAT.
with s (Col1, Col2) as (
select 'A', 1 from dual union all
select 'A', 2 from dual union all
select 'A', 3 from dual union all
select 'B', 1 from dual union all
select 'B', 2 from dual union all
select 'B', 3 from dual)
select col1, ltrim(sys_connect_by_path(col2, ','), ',') path
from s
start with col2 = 1
connect by prior col2 = col2 - 1 and prior col1 = col1;
C PATH
- ----------
A 1
A 1,2
A 1,2,3
B 1
B 1,2
B 1,2,3
6 rows selected.
The database scheme consists:
Table1(code, col1, col2, col3, col4, col5)
What to do is:
For the Table1 with the maximal code value from Table1 table, obtain all its characteristics (except for a code) in two columns:
The name of the characteristic (a name of a corresponding column in the PC table);
Value of the characteristic.
I don't have any idea how to get the table column names in my result column set.
The final result will look like:
chr value
col1 133
col2 80
col3 28
col4 2
col5 50
This is an unpivot operation. The simplest way is using union all. However, the following is generally more efficient:
select (case when n.n = 1 then 'col1'
when n.n = 2 then 'col2'
when n.n = 3 then 'col3'
when n.n = 4 then 'col4'
when n.n = 5 then 'col5'
end) as chr,
(case when n.n = 1 then col1
when n.n = 2 then col2
when n.n = 3 then col3
when n.n = 4 then col4
when n.n = 5 then col5
end) as value
from table t cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all select 5
) n;
This is more efficient when your table is big or a complicated subquery.
The union all version is:
select 'col1', col1 from table t union all
select 'col2', col2 from table t union all
select 'col3', col3 from table t union all
select 'col4', col4 from table t union all
select 'col5', col5 from table t;
SELECT 'col1', MAX(col1) FROM table1
UNION
SELECT 'col2', MAX(col2) FROM table1
UNION
...
SELECT 'cd' as chr, cd as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'model' as chr, cast(model as varchar)as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'speed' as chr,cast(speed as varchar) as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'ram' as chr, cast(ram as varchar) as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'hd' as chr, cast(hd as varchar) as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'price' as chr,cast(price as varchar) as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
Select char, value
From
(Select code,
cast(speed as varchar(20)) speed,
cast(ram as varchar(20)) ram,
cast(hd as varchar(20)) hd,
cast(model as varchar(20)) model,
cast(cd as varchar(20)) cd,
cast(price as varchar(20)) price
FROM pc
) src
UNPIVOT
(value For char in (speed,ram,hd,model,cd,price)
) As unpvt
where
code in (Select max(code) from PC)`
I'm trying to search duplicate rows by several columns in large table (near 18 000 rows). Problem is that queries take a lot of time, I tried this:
SELECT * FROM table_name a, table_name b
WHERE a.col1 = b.col1
AND a.col2 = b.col2
AND a.col3 = b.col3
AND a.col4 = b.col4
AND a.id <> b.id
and this:
SELECT *
FROM table_name
WHERE col1 IN (
SELECT col1
FROM table_name
GROUP BY col1
HAVING count(col1) > 1
)
AND col2 IN (
SELECT col2
FROM table_name
GROUP BY col2
HAVING count(col2) > 1
)
AND col3 IN (
SELECT col3
FROM table_name
GROUP BY col3
HAVING count(col3) > 1
)
AND col4 IN (
SELECT col4
FROM table_name
GROUP BY col4
HAVING count(col4) > 1
)
they both work, but too slow. Any ideas?
You can try using one joint GROUP BY statement like:
SELECT * FROM table_name
GROUP BY col1, col2, col3, col4
HAVING count(*) > 1
At the very least, it will look cleaner.
EDIT
To return all results as a sub-set for the previous column:
SELECT *
FROM table_name
WHERE col4 IN (
SELECT col4
FROM table_name
WHERE col3 IN (
SELECT col3
FROM table_name
WHERE col2 IN (
SELECT col2
FROM table_name
WHERE col1 IN (
SELECT col1
FROM table_name
GROUP BY col1
HAVING count(col1) > 1
)
)
)
This, in concept, should give you all results in a faster execution time.
there are a lot of questions about Recursive SELECT query in Mysql, but most of answers is that "There NO solution for Recursive SELECT query in Mysql".
Actually there is a certain solution & I want to know it clearly, so this question is the following of the previous question that can be found at (how-to-do-the-recursive-select-query-in-mysql)
Suppose you have this table:
col1 - col2 - col3
1 - a - 5
5 - d - 3
3 - k - 7
6 - o - 2
2 - 0 - 8
& you want to find all the links that connect to value "1" in col1, i.e. you want to print out:
1 - a - 5
5 - d - 3
3 - k - 7
Then you can use this simple query:
select col1, col2, #pv:=col3 as 'col3' from table1
join
(select #pv:=1)tmp
where col1=#pv
Ok, good, however, if your table has 2 records containing "1" in col1 & 2 records containing "3" in col1, ex:
col1 - col2 - col3
1 - a - 5
1 - m - 9
5 - d - 3
3 - k - 7
6 - o - 2
3 - v - 10
2 - 0 - 8
Then, when users search for "1" in col1, it should show all the links connecting to 2 "1", i.e. it should show this expecting result:
col1 - col2 - col3
1 - a - 5
1 - m - 9
5 - d - 3
3 - k - 7
3 - v - 10
So, my question is how do we modify the above query so that it will show all the links as in the above expecting result?
EDIT: # Gordon,
but if we omit select distinct col1, col2 from then this query means something, can you work on this (since the childID got increased, so we can order the table1 ):
select col1, col2,
#pv:=(case when find_in_set(col3, #pv) then #pv else concat(#pv, ',', col3)
end) as 'col3'
from (select * from table1 order by col1) tb1 join
(select #pv:='1') tmp
on find_in_set(col1, #pv) > 0
In this case, we don't worry about the order, for example, if this is the data:
col1 - col2 - col3
4 - a - 5
1 - d - 2
1 - k - 4
2 - o - 3
6 - k - 8
8 - o - 9
the output will be:
col1 - col2 - col3
1 - d - 1,2
1 - k - 1,2,4
2 - o - 1,2,4,3
So we get this result 1,2,4,3 right? & we just select all records if the col1 is in 1,2,4,3. Then we can get the final expected result.
If that is the case, can you think of any special case that rules out the solution I just mentioned?
I keep wondering if something like this would work:
select distinct col1, col2
from (select col1, col2,
#pv:=(case when find_in_set(col3, #pv) then #pv else concat(#pv, ',', col3)
end) as 'col3'
from table1 join
(select #pv:='1') tmp
on find_in_set(col1, #pv) > 0
) t
Something like this should work for small data sets. However, the idea of putting all the ids in a string is limited to the capacity of a string.
In my limited deep of hierarchy-levels, I used the following:
parents:
select * from mytable
join (
select A.id Aid,B.id Bid, C.id Cid, D.id Did, E.id Eid, F.id Fid,G.id Gid, H.id Hid from mytable A
left join mytable B on B.id=A.parent
left join mytable C on C.id=B.parent
left join mytable D on D.id=C.parent
left join mytable E on E.id=D.parent
left join mytable F on F.id=E.parent
left join mytable G on G.id=F.parent
left join mytable H on H.id=G.parent
where A.id=9
) X
where id in (Aid,Bid,Cid,Did,Eid,Fid,Gid,Hid);
children:
select * from mytable where id in (
select distinct id from mytable
join (
select A.id Aid,B.id Bid, C.id Cid, D.id Did, E.id Eid, F.id Fid,G.id Gid, H.id Hid FROM mytable A
left join mytable B on B.parent=A.id
left join mytable C on C.parent=B.id
left join mytable D on D.parent=C.id
left join mytable E on E.parent=D.id
left join mytable F on F.parent=E.id
left join mytable G on G.parent=F.id
left join mytable H on H.parent=G.id
Where A.id=1
) X
where id in (Aid,Bid,Cid,Did,Eid,Fid,Gid,Hid)
);
Had more of a play. Can't get it to work using the user variables due to the ordering of items.
However if you have a reasonable maximum number of levels then you can do something like this:-
SELECT CONCAT_WS('-', a.allCols, b.allCols, c.allCols, d.allCols, e.allCols, f.allCols, g.allCols, h.allCols, i.allCols, j.allCols, k.allCols, l.allCols, m.allCols)
FROM (SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) a
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) b ON a.col3 = b.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) c ON b.col3 = c.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) d ON c.col3 = d.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) e ON d.col3 = e.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) f ON e.col3 = f.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) g ON f.col3 = g.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) h ON g.col3 = h.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) i ON h.col3 = i.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) j ON i.col3 = j.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) k ON j.col3 = k.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) l ON k.col3 = l.col1
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) m ON l.col3 = m.col1
WHERE a.col1 = 1
This is coping with up to 13 levels (OK, only a couple used in your test data), and will give a comma separated bit for each column, with each row joined with a dash (-).
Stored procedure is the best way to do it. Because Gordon's solution would work only if the data follows the same order.
If we have a table structure like this
col1 - col2 - col3
3 - k - 7
5 - d - 3
1 - a - 5
6 - o - 2
2 - 0 - 8
It wont work.
Here is a sample procedure code to achieve the same.
delimiter //
CREATE PROCEDURE chainReaction
(
in inputNo int
)
BEGIN
declare final_id int default NULL;
SELECT col3 into final_id from table1
where col1 = inputNo;
if( final_id is not null) then
insert into results(select col1, col2, col3 from table1 where col1 = inputNo);
CALL chainReaction(final_id);
end if;
END//
delimiter ;
call chainReaction(1);
select * from results;
drop table if exists results;
I have a table in MySQL:
Col1 | Col2
a A
a B
c C
a B
i want to create a table like this:
col1 | col2 | freq
a A 0.33
a B 0.67
col1 is a specified item in Col1. col2 is distinct item that has occured with the specified item(i.e. a). freq column is the frequency of appearence of item in col2.
Can someone give me a hint of how to create such a query? Thanks a lot.
try this:
Select A.Col1, A.Col2, A.Count1 * 1.0 / B.Count2 As Freq
From (
Select Col1, Col2, Count(*) As Count1
From YourTableName
Group By Col1, Col2
) As A
Inner Join (
Select Col1, Count(*) As Count2
From YourTableName
Group By Col1
) As B
On A.Col1 = B.Col1
You can also use this which is coded in SQL server
DECLARE #Count INT;
SELECT #Count = COUNT(1) FROM YourTableName WHERE Col1 = 'a'
SELECT Col1, Col2, CAST(COUNT(1)* 1.00 /#Count AS DECIMAL(4,2) ) AS Frequency
FROM YourTableName
WHERE Col1 = 'a'
GROUP BY Col1, Col2
this way you have a better performance
With window functions
SELECT Col1, Col2, Count1*1.0 / Count2 AS freq
FROM (
SELECT
Col1,
Col2,
COUNT() OVER(PARTITION BY Col1, Col2) AS Count1,
COUNT() OVER(PARTITION BY Col1) AS Count2
FROM YourTableName
)
GROUP BY Col1, Col2