divide one record into multiple ones - sql

I need a query to change this:
col1 col2 col3
1 2 abc
3 4 cd
4 5 null
To this
col1 col2 col3
1 2 a
1 2 b
1 2 c
3 4 c
3 4 d
4 5 NULL
Thank you.

Try it like this
EDIT shorter syntax for the running numbers
EDIT2 JamieD77's comment to include the TOP into the creation of the numbers
CREATE FUNCTION dbo.SingleChars(#SomeText NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN
WITH nr10 AS
(
SELECT * FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tbl(A)
)
,RunningNumbers AS
(
SELECT TOP (ISNULL(LEN(#SomeText),0)) ROW_NUMBER() OVER(ORDER BY (SELECT(NULL))) AS Nmbr FROM nr10,nr10 AS a,nr10 AS b,nr10 AS c,nr10 AS d,nr10 AS e,nr10 AS f,nr10 AS g
)
SELECT SUBSTRING(#SomeText,Nmbr,1) AS TheCharacter
,ASCII(SUBSTRING(#SomeText,Nmbr,1)) AS ASCII_Code
FROM RunningNumbers;
A test
SELECT * FROM dbo.SingleChars('This is a test');
The result
T 84
h 104
i 105
s 115
32
i 105
s 115
32
a 97
32
t 116
e 101
s 115
t 116
Now your problem
DECLARE #tbl TABLE(col1 INT, col2 INT, col3 VARCHAR(100));
INSERT INTO #tbl VALUES(1,2,'abc'),(3,4,'cd'),(4,5,NULL);
SELECT col1,col2,sc.TheCharacter
FROM #tbl
OUTER APPLY dbo.SingleChars(col3) AS sc;
The result
1 2 a
1 2 b
1 2 c
3 4 c
3 4 d
4 5 NULL

In MSSQL you can use recursive CTE. Just take one left letter on each step:
WITH T1 as
(
SELECT col1,col2,LEFT(col3,1) as col4, SUBSTRING(col3,2,10000) as col3
FROM Table1
UNION ALL
SELECT col1,col2,LEFT(col3,1) as col4, SUBSTRING(col3,2,10000) as col3
FROM T1 WHERE Col3 <> ''
)
SELECT col1,col2,col4 FROM T1 ORDER BY col1,col2;
one more query:
WITH T1 as
(
SELECT col1,col2,LEFT(col3,1) as col4, col3, 2 as nextPoint
FROM Table1
UNION ALL
SELECT col1,col2,SUBSTRING(col3,nextPoint,1) as col4, col3,
nextPoint+1 as nextPoint
FROM T1 WHERE LEN(col3)>=nextPoint
)
SELECT col1,col2,col4 FROM T1 ORDER BY col1,col2;

Related

SQL Postgres union data with missed values

I have two results of queries:
id | col1 | col2 | col3
1 1 null 3j
2 2 12 35
3 null 32 31
4 null 43 33
5 null 44 4
id | col1 | col2 | col3
6 1 null 3j
7 2 null 35
8 3 null 31
9 4 null 33
10 5 null null
I need to do union:
id | col1 | col2 | col3
6 1 null 3j
7 2 12 35
8 3 32 31
9 4 43 33
10 5 null null
5 null 44 4
The problem is some values are missing
I wrote this big sql query to solve this problem:
select *
from (
select max(id) as id,
max(col1) as col1,
max(col2) as col2,
max(col3) as col3
from (
select max(id) as id,
max(col1) as col1,
max(col2) as col2,
max(col3) as col3
from (
select max(id) as id,
max(col1) as col1,
max(col2) as col2,
max(col3) as col3
from (
select *
from t1
where id = 1
union
select *
from t2
where id = 2
) t
group by case
when col1 is null
or
length(col1) =
0 then id
else col1 end
) t1
group by case
when col2 is null
or length(col2) = 0
then id
else col2 end
) t2
group by case
when col3 is null
or length(col3) = 0 then id
else col3 end
) t3
may be are there some ideas to simplify it? Or are there other approaches to enrich data efficiently, because I also need to do intersection, right, left, inner union and I don't want to build so monsters queries
well you cat try something like this:
union
select max(col1),
max(col2),
max(col3)
from t1
where id = 1
or id = 2
group by coalesce(nullif(col1, ''),
nullif(col2, ''),
nullif(col3, ''));
upd:
outer union
select max(col1),
max(col2),
max(col3)
from t1
where id = 1
or id = 2
group by coalesce(nullif(col1, ''),
nullif(col2, ''),
nullif(col3, ''))
having count = 1;
inner union
select max(col1),
max(col2),
max(col3)
from t1
where id = 1
or id = 2
group by coalesce(nullif(col1, ''),
nullif(col2, ''),
nullif(col3, ''))
having count > 1;
left and right are outer intersect with common query with 'where'

Sql Query for Unique and Duplicates in oracle sql?

I need to display unique records in one column and duplicates in another column in Oracle?
COL1 COL2
1 10
1 10
2 20
3 30
3 30
unique in one set duplicate in one set
col1 col2 col1 col2
2 20 1 10
1 10
3 30
3 30
You can use the group by for both cases with the having clause:
Unique records
select *
from table as t
inner join (
select col1, col2, count(*) as times
from table
group by col1, col2
having count(*) = 1) as t2 ON t.col1 = t2.col2 and t.col2 = t2.col2
Duplicate records:
select *
from table as t
inner join (
select col1, col2, count(*) as times
from table
group by col1, col2
having count(*) > 1) as t2 ON t.col1 = t2.col1 and t.col2 = t2.col2
Would something like this do? See comments within code.
SQL> with
2 test (col1, col2) as
3 -- sample data
4 (select 1, 10 from dual union all
5 select 1, 10 from dual union all
6 select 2, 20 from dual union all
7 select 3, 30 from dual union all
8 select 3, 30 from dual
9 ),
10 uni as
11 -- unique values
12 (select col1, col2
13 from test
14 group by col1, col2
15 having count(*) = 1
16 ),
17 dup as
18 -- duplicate values
19 (select col1, col2
20 from test
21 group by col1, col2
22 having count(*) > 1
23 )
24 -- the final result
25 select u.col1 ucol1,
26 u.col2 ucol2,
27 d.col1 dcol1,
28 d.col2 dcol2
29 from uni u full outer join dup d on u.col1 = d.col1;
UCOL1 UCOL2 DCOL1 DCOL2
---------- ---------- ---------- ----------
1 10
3 30
2 20
SQL>
You can identify the duplicate values using window functions, and then filter each query. Then to get unique records:
select col1, col2
from (select t.*, count(*) over (partition by col1) as cnt
from t
) t
where cnt = 1;
To get duplicates:
select col1, col2
from (select t.*, count(*) over (partition by col1) as cnt
from t
) t
where cnt > 1;

Calculate percentage for a given date range in sql procedure

Table Structure:
Col1 col2 col3 col4
1 ABC q 03-11-2018
2 ABC q 03-11-2018
3 ABC q 03-11-2018
4 PBC q 03-11-2018
5 ABC q 04-11-2018
6 ABC q 04-11-2018
7 ABC q 05-11-2018
Expected O/P:
calculate percentage by the following formula
count(col2) where col=ABC & total rows count
suppose user give date between 03-11-2018 to 05-11-2018 then output should be
col1 col2 col3
3 3 100%
2 2 100%
1 1 100%
You can try like following.
DECLARE #StartDate DATE='03-11-2018'
DECLARE #EndDate DATE = '05-11-2018';
;WITH cte AS
(SELECT Count(*) col1,
col4
FROM temp_table
WHERE col2 = 'ABC'
GROUP BY col4)
SELECT col1,
col2,
Str(col1 * 100.0/col2, 12, 2) + '%' AS Col3
FROM cte c
CROSS apply (SELECT Count(*) col2
FROM temp_table T
WHERE C.col4 = T.col4)TOT
WHERE C.col4 BETWEEN #StartDate AND #EndDate
Online Demo
Note: Replace TEMP_TABLE with your actual table name.

Count of one of the columns

Let's say I have the dataset that looks like:
col1 col2 col3
a 2 20
a 3 12
a 4 34
b 2 44
c 3 23
c 5 13
....
What I want is a count of col1.
Output:
col1 col2 col3 count
a 2 20 3
a 3 12 3
a 4 34 3
b 2 44 1
c 3 23 2
c 5 13 2
.......
I know I can do by:
with cte as (
select col1, count(*) count
from tab1)
select a.col1,a.col2,a.col3,cte.count
from tab1
join cte on a.col1=cte.col1
But is there any other I can do that without cross apply or cte?
Also, assuming there are more than 3 letters in col1, so I couldn't use sum function either:
SUM(CASE WHEN ItemID = 'a' THEN 1 ELSE 0 END) AS count_a
If you're using SQL Server 2008+, you can use COUNT() OVER():
SELECT *,
COUNT(*) OVER(PARTITION BY col1)
FROM tab1
ONLINE DEMO

How to select duplicate columns data from table

Have table like :
col1 col2 col3 col4 col5
test1 1 13 15 1
test2 1 13 15 4
test3 2 7 3 5
test4 3 11 14 18
test5 3 11 14 8
test6 3 11 14 11
Want select col1,col2,col3,col4 data where col2,col3,col4 are duplicates
for example it must be :
col1 col2 col3 col4
test1 1 13 15
test2 1 13 15
test4 3 11 14
test5 3 11 14
test6 3 11 14
How to do it ?
Presuming SQL-Server >= 2005 you can use COUNT(*) OVER:
WITH CTE AS
(
SELECT col1, col2, col3, col4, cnt = COUNT(*) OVER (PARTITION BY col2, col3, col4)
FROM dbo.TableName t
)
SELECT col1, col2, col3, col4
FROM CTE WHERE cnt > 1
Demo
If I understand correctly:
select col1, col2, col3, col4
from table t
where exists (select 1 from table t2 where t2.col1 = t.col1 and t2.col1 <> t.col1) and
exists (select 1 from table t2 where t2.col2 = t.col2 and t2.col1 <> t.col1) and
exists (select 1 from table t2 where t2.col3 = t.col3 and t2.col1 <> t.col1);
Simple Join can work
select m1.col1,m1.col2,m1.col3,m1.col4 from Mytable m1
join Mytable m2
on m1.col2 =m2.col2
and m1.col3=m2.col3
and m1.col4 =m2.col4
You can use the following code for that:
SELECT * FROM your_table
MINUS
SELECT DISTINCT * FROM your_table
EDIT: sorry this works only for complete duplicates. If you want to exclude the first column, you can use
SELECT col2,col3,col4 FROM your_table
MINUS
SELECT DISTINCT col2,col3,col4 FROM your_table
and afterwards make a join with the table itself (ON its primary keys).