Spliting a single column into two different columns SQL Server [closed] - sql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have something like this:
Column
1
2
3
4
-1
-2
-3
-4
And I wanted an output something like this:
C1 C2
1 -1
2 -2
3 -3
4 -4
Can anyone help me on writing a query to get this output in T-SQL??
and what if something is like this:
values
1
-5
10
-9
15
-3
8
-11
12
-17
and I have to make two columns that separates the positive values in one column and negative values in another.

You can use aggregation:
select max(col1), min(col1)
from t
group by abs(col1);

This will do what you want.. a simple self-join
create table test1
(
col1 int not null
)
insert into test1 (col1) values (1)
insert into test1 (col1) values (2)
insert into test1 (col1) values (3)
insert into test1 (col1) values (4)
insert into test1 (col1) values (-1)
insert into test1 (col1) values (-2)
insert into test1 (col1) values (-3)
insert into test1 (col1) values (-4)
select a.col1 C1, b.col1 C2 from test1 a
join test1 b on a.col1 = -b.col1
where a.col1 > 0

SELECT t1.col1 as C1,
t2.col1 AS C2
FROM tbl t1
JOIN tbl t2
ON t1.col1 = (t2.col1 * -1)
WHERE t1.col1 > 0
GO
C1 | C2
-: | -:
1 | -1
2 | -2
3 | -3
4 | -4
dbfiddle here

You can join the values of the two queries by using the analytic function ROW_NUMBER():
WITH A AS (
SELECT col1, ROW_NUMBER() OVER (ORDER BY col1 desc) AS row_num
FROM TABLE_1
WHERE col1 < 0),
B AS (
SELECT col1, ROW_NUMBER() OVER (ORDER BY col1) AS row_num
FROM TABLE_1
WHERE col1 >= 0)
SELECT A.col1 AS C1, B.col1 AS C2
FROM A
INNER JOIN B
ON A.row_num = B.row_num;

You have to JOIN the table with itself and then limit the result so the negative ones are excluded from the first column
SELECT t1.Col1 c1, t2.Col1 c2 FROM tbl t1
JOIN tbl t2 ON t1.Col1 = t2.Col1*-1 AND t1.Col1 > 0
Answer to second question:
The idea is to SELECT positive and negative numbers separately and then do a FULL OUTER JOIN on their row numbers.
SELECT t1.Col1 c1, t2.Col1 c2 FROM (
SELECT t11.Col1,
ROW_NUMBER() OVER(ORDER BY t11.Col1 ASC) rn
FROM tbl t11
WHERE t11.Col1 > 0
) t1 FULL JOIN (
SELECT t22.Col1,
ROW_NUMBER() OVER(ORDER BY t22.Col1 DESC) rn
FROM tbl t22
WHERE t22.Col1 < 0
) t2 ON t2.rn = t1.rn;
Example:
CREATE TABLE tbl ( Col1 int );
INSERT INTO tbl VALUES (6), (7), (-4), (1), (-2), (3), (5);
-- RESULT
| c1 | c2 |
|----|--------|
| 1 | -2 |
| 3 | -4 |
| 5 | (null) |
| 6 | (null) |
| 7 | (null) |

Related

SQL Compare rows of a table with multiple columns

I have a table T1
Id
Col1
Col2
IsActive
1
T1
v1
1
2
T2
v2
0
Now received the following data and it need to be inserted into the above table.
| Col1 | Col2 |
|--------|--------|
| T1 | v1 |
| T2 | v2 |
| T3 | v3 |
As this data contains some duplicated values, it need to be inserted based on IsActive Column value. For row with IsActive 1, need to insert with IsActive 2 and for row with IsActive 0, need to insert with IsActive 1 like below, the unique data need to be inserted with IsActive 1 and that is not a problem right now
Id
Col1
Col2
IsActive
1
T1
v1
1
2
T2
v2
0
3
T1
v1
2
4
T2
v2
1
5
T3
v3
1
I have created a Temp table #Temp and inserted common rows in new incoming data and data from existing table like below:
#Temp
Col1
Col2
IsActive
T1
v1
1
T2
v2
0
T1
v1
NULL
T2
v2
NULL
Using Group By I can able to select duplicate rows but I need to insert based on IsActive value, so I stuck here.
insert into T1
select Col1, Col2, '1' from #Temp
GROUP BY Col1, Col2
HAVING COUNT(Col1) > 1
I need help on this above part, thanks in advance
Try this:
-- create temp table with values to be inserted
INSERT INTO #ToInsert
([Col1], [Col2])
VALUES
('T1', 'v1'),
('T2', 'v2'),
('T3', 'v3')
-- join each value of the temp table to the original table. if
-- value exists increment its `IsActive` by 1, otherwise set it to 1
INSERT INTO t (Col1, Col2, IsActive)
SELECT i.Col1, i.Col2, COALESCE(t.IsActive + 1, 1) AS IsActive
FROM #ToInsert i
LEFT JOIN (
SELECT Col1, Col2, max(IsActive) as IsActive
FROM t
GROUP BY Col1, Col2
) t ON i.Col1 = t.Col1 AND i.Col2 = t.Col2
Demo here

SQL - Pick first row satisfying a condition below every row satisfying another condition

Suppose I have this table, named Table
+----+------+------+
| ID | Col1 | Col2 |
+----+------+------+
| 1 | A | 0 |
| 2 | B | 0 |
| 3 | C | 1 |
| 4 | A | 1 |
| 5 | D | 0 |
| 6 | A | 0 |
| 7 | F | 1 |
| 8 | H | 1 |
+----+------+------+
I want this result:
+----+------+------+
| ID | Col1 | Col2 |
+----+------+------+
| 3 | C | 1 |
| 4 | A | 1 |
| 7 | F | 1 |
+----+------+------+
That is:
If Col1 = A and Col2 = 1, take the corresponding row
If Col1 = A and Col2 = 0, take the first row below it where Col2 = 1
I tried something like
SELECT CASE
WHEN t.Col2 > 0
THEN t.Col2
WHEN t1.Col2 > 0
THEN t1.Col2
WHEN t2.Col2 > 0
THEN t2.Col2
...
FROM Table t
JOIN table t1 ON t.id - 1 = t1.id
JOIN table t2 ON t.id - 2 = t2.id
...
WHERE t.Col2 = 'A'
but it's not quite what I was looking for.
I couldn't come up with any solution. What should I do?
Use window functions SUM() and MIN():
with
cte1 as (
select *, sum(case when col1 = 'A' and col2 = 0 then 1 else 0 end) over (order by id) grp
from tablename
),
cte2 as (
select *, min(case when col2 = 1 then id end) over (partition by grp order by id) next_id
from cte1
)
select id, col1, col2
from cte2
where (col1 = 'A' and col2 = 1) or (id = next_id)
See the demo.
Results:
> id | col1 | col2
> -: | :--- | ---:
> 3 | C | 1
> 4 | A | 1
> 7 | F | 1
Hmmm . . . I am thinking lag():
select t.*
from (select t.*,
lag(col1) over (order by id) as prev_col1,
lag(col2) over (order by id) as pev_col2
from t
) t
where col1 = 'A' and col2 = 1 or
(pev_col1 = 'A' and prev_col2 = 0);
Here is a query that finds all such rows you asked for where either it's Col1=A and Col2=1 or it's the first Col2=1 following a Col1=A and Col2=0.
A brief explanation is the query only considers rows where Col2=1. It takes the row if Col1=A of course. But it also takes the row if it looks back to find the closest previous row with Col2=1 as well as the closest previous row where Col1=A and Col2=0 and it finds former is further back than the latter (or the former doesn't exist).
create table MyTable (
ID int not null identity(1,1),
Col1 varchar(100) not null,
Col2 varchar(100) not null
);
insert MyTable (Col1, Col2) values ('A', '0');
insert MyTable (Col1, Col2) values ('B', '0');
insert MyTable (Col1, Col2) values ('C', '1');
insert MyTable (Col1, Col2) values ('A', '1');
insert MyTable (Col1, Col2) values ('D', '0');
insert MyTable (Col1, Col2) values ('A', '0');
insert MyTable (Col1, Col2) values ('F', '1');
insert MyTable (Col1, Col2) values ('H', '1');
select * from MyTable;
select *
from MyTable as t
where t.Col2 = 1
and (t.Col1 = 'A'
or isnull((select top (1) t2.ID
from MyTable as t2
where t2.ID < t.ID
and t2.Col2 = 1
order by t2.ID desc
), 0)
<
(select top (1) t2.ID
from MyTable as t2
where t2.ID < t.ID
and t2.Col1 = 'A'
and t2.Col2 = 0
order by t2.ID desc
)
)
order by t.ID;

Query different number of records for each category in SQL

I have a table that looks like the following:
col1 | col2 | col3 | col4
A | 1 | 2 | 4
A | 2 | 5 | 3
A | 5 | 1 | 6
B | 3 | 1 | 2
B | 4 | 4 | 4
I have another table where the records are unique and looks like the following:
col1 | col2
A | 2
B | 1
I want to query Table 1 in such a way that I filter out only n number of records for each category in Table 1 based on the value the categories have in Table 2.
Based on Table 2 I need to extract 2 records for A and 1 record for B. I need the resulting queried table to look like the following:
col1 | col2 | col3 | col4
A | 2 | 5 | 3
A | 1 | 2 | 4
B | 3 | 1 | 2
The choice of the records are made based on col4 sorted in ascending order. I am currently tring to do this on BigQuery.
You can use row_number() and join:
select t1.col1, t1.col2, t1.col3, t1.col4
from (select t1.*, row_number() over (partition by col1 order by col4) as seqnum
from table1 t1
) t1 join
table2 t2
on t2.col1 = t1.col1 and t1.seqnum <= t2.col2
order by t1.col1, t1.col4;
Below is for BigQuery Standard SQL
#standardSQL
SELECT t.*
FROM (
SELECT ARRAY_AGG(t1 ORDER BY t1.col4) arr, MIN(t2.col2) cnt
FROM table1 t1 JOIN table2 t2 ON t1.col1 = t2.col1
GROUP BY t1.col1
), UNNEST(arr) t WITH OFFSET num
WHERE num < cnt
you can test / play with it using dummy data from your question as below
#standardSQL
WITH `table1` AS (
SELECT 'A' col1, 1 col2, 2 col3, 4 col4 UNION ALL
SELECT 'A', 2, 5, 3 UNION ALL
SELECT 'A', 5, 1, 6 UNION ALL
SELECT 'B', 3, 1, 2 UNION ALL
SELECT 'B', 4, 4, 4
), `table2` AS (
SELECT 'A' col1, 2 col2 UNION ALL
SELECT 'B', 1
)
SELECT t.*
FROM (
SELECT ARRAY_AGG(t1 ORDER BY t1.col4) arr, MIN(t2.col2) cnt
FROM table1 t1 JOIN table2 t2 ON t1.col1 = t2.col1
GROUP BY t1.col1
), UNNEST(arr) t WITH OFFSET num
WHERE num < cnt
with output as
Row col1 col2 col3 col4
1 A 2 5 3
2 A 1 2 4
3 B 3 1 2

SQL Split Single Row into Fixed Number of Columns

We need to split a single row into fixed number of multiple columns. Following is an example for the data set:
1
2
3
4
5
6
7
Desired Output:
Column A Column B Column C Column D
1 2 3 4
5 6 7 NULL
Thanks for your help in advance.
SQL Server Solution:
Create Sample Table:
create table mytable (col1 int)
insert into mytable values
(1),
(2),
(3),
(4),
(5),
(6),
(7);
Using Modulo and Row_Number(), you could easily do this:
Modulo Query:
SELECT
R1.col1 as columnA,
R2.col1 as columnB,
R3.col1 as columnC,
R4.col1 as columnD
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum, col1
FROM mytable
WHERE
col1 % 4 = 1
) AS R1
FULL OUTER JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum, col1
FROM mytable
WHERE
col1 % 4 = 2
) AS R2
ON R1.RowNum = R2.RowNum
FULL OUTER JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum, col1
FROM mytable
WHERE
col1 % 4 = 3
) AS R3
ON R2.RowNum = R3.RowNum
FULL OUTER JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum, col1
FROM mytable
WHERE
col1 % 4 = 0
) AS R4
ON R4.RowNum = R3.RowNum
Result:
+---------+---------+---------+---------+
| columnA | columnB | columnC | columnD |
+---------+---------+---------+---------+
| 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | (null) |
+---------+---------+---------+---------+
SQL Fiddle Demo

Find matching column data between two rows in the same table

I want to find the matching value between two rows in the same sqlite table. For example, if I have the following table:
rowid, col1, col2, col3
----- ---- ---- ----
1 5 3 1
2 3 6 9
3 9 12 5
So comparing row 1 and 2, I get the value 3.
Row 2 and 3 will give 9.
Row 3 and 1 will give 5.
There will always be one and only one matching value between any two rows in the table.
What it the correct sqlite query for this?
I hardcoded the values for the rows because i do not know how to declare variables in sqllite.
select t1.rowid as r1, t2.rowid as r2, t2.col as matchvalue from <yourtable> t1 join
(
select rowid, col1 col from <yourtable> where rowid = 3 union all
select rowid, col2 from <yourtable> where rowid = 3 union all
select rowid, col3 from <yourtable> where rowid = 3
) t2
on t2.col in (t1.col1, t1.col2, t1.col3)
and t1.rowid < t2.rowid -- you don't need this if you have two specific rows
and t1.rowid = 1
select col from
(
select rid, c1 as col from yourtable
union
select rid, c2 from yourtable
union
select rid, c3 from yourtable
) v
where rid in (3,2)
group by col
order by COUNT(*) desc
limit 1