SQL Server : join all left table and repeat right - sql

I have to join tables in a following way:
Table A:
1
2
3
4
5
Table B:
A
B
The result table should be:
1 A
2 B
3 A
4 B
5 A
Do you have any ideas how to do this?

Assuming worst case, the column in table A is not a sequence without gaps and the number of rows in table B is not known in advance, you must apply a ROW_NUMBER on both tables and then join on a MODULO:
SELECT col1, col2
FROM
(
SELECT col1,
ROW_NUMBER() OVER (ORDER BY col1) -1 AS rn
FROM tableA
) AS A
JOIN
(
SELECT col2,
ROW_NUMBER() OVER (ORDER BY col2) -1 AS rn
FROM tableB
) AS B
ON A.rn % (SELECT COUNT(*) FROM tableB) = B.rn

Maybe something like this:
select A.nr, case when (A.nr%2=0) then b2.chr else b3.chr end letter
from A, B b2, B b3
where b2.chr = 'A' and b3.chr = 'B'

Related

SQL - Update Rows from a list of values

So Table Setup is:
Column1 Column2 Column3
A 1 Null
B 2 Null
C 1 Null
D 2 Null
E 1 Null
F 2 Null
G 1 Null
H 2 Null
I would like to update Column3 with an array of values (Value1, Value2, Value3) and cycle through that list until the update is complete
The ultimate goal is for the table to look like this:
Column1 Column2 Column3
A 1 Value1
B 2 Value2
C 1 Value3
D 2 Value1
E 1 Value2
F 2 Value3
G 1 Value1
H 2 Value2
I originally tried in powershell but it was not working as I would have liked because of how the data is being imported, so now I am looking towards SQL. Any suggestions would be great!
You could try an update join here. The approach below is to assign an ordered sequence to both your original table and the "array" of values for updating. We join using modulus logic, such that your table's sequence ordering will match up the values in the array and will wrap around until all values have been assigned.
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY Column1) rn
FROM yourTable
)
UPDATE t1
SET Column3 = t2.val
FROM cte t1
INNER JOIN
(
SELECT 1 AS id, 'Value1' AS val UNION ALL
SELECT 2, 'Value2' UNION ALL
SELECT 3, 'Value3'
) t2
ON t2.id = 1 + ((t1.rn - 1) % 3);
Demo
Assuming you can put the "array" in a table, you can use something like this:
with vals as (
select v.*,
row_number() over (order by (select null)) - 1 as seqnum,
count(*) over () as cnt
from (values ('Value1'), ('Value2'), ('Value3')) v(val)
)
update t
set t.column3 = v.val
from (select t.*,
row_number() over (order by column1) - 1 as seqnum
from t
) t join
vals v
on t.seqnum % v.cnt = v.seqnum;
The basic idea is to enumerate the rows in each table and then use modulo arithmetic to match them.

Return rows where specific column has duplicate values

From the table below I want to show the two rows where the values in column 3 are duplicates:
ID
Col2
Col3
1
a
123
2
b
123
3
c
14
4
d
65
5
e
65
This means that the query that I need should return rows with ID 1, 2 and 4, 5.
I wrote query using having:
SELECT *
FROM t1
INNER JOIN (SELECT col3 FROM t1
GROUP BY col3
HAVING COUNT(*) > 1) a
ON t1.col3 = a.col3
This query though only returns 1 and 4 rows for example, not all duplicates.
I would appreciate the help.
Your query should work, but I would suggest window functions:
select t1.*
from (select t1.*, count(*) over (partition by col3) as cnt
from t1
) t1
where cnt > 1;

How can I write a SQL Server stored procedure to get the following output?

I have a SourceTable like this with 2 column names:
Col 1 | Col 2
------------------
A | 2
B | 3
C | 4
D | 2
E | 1
F | 0
The first column has some letter, and the second column carries its frequency.
We need to write a stored procedure and get the output in a TargetTable like this.
We CAN NOT use any loop, or iteration for this.
Col 1
-----
A
A
B
B
B
C
C
C
C
D
D
E
How about a recursive CTE?
with x as (
select col1, 1 as i, col2 as lim
from t
where col2 > 0
union all
select col1, i + 1, lim
from x
where i + 1 <= lim
)
select col1
from x
order by col1;
Assumes there is a low known max value for Col2 (in this case 10):
select Col1 from tbl
inner join (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) T(n)
on T.n <= tbl.Col2
If you don't want to use a recursive cte or have a table of numbers, you can use master..spt_values to generate your numbers for you:
declare #t table(Col1 nvarchar(1), Col2 int);
insert into #t values
('A',2),('B',3),('C',4),('D',2),('E',1),('F',0);
with rn as
( -- This sub select simply makes sure you only get the maximum number required.
select top (select max(Col2) from #t) row_number() over (order by (select null)) as rn
from master..spt_values t1
cross join master..spt_values t2
)
select t.Col1
from #t t
inner join rn
on(t.Col2 >= rn.rn)
order by t.Col1
I'd use a table of numbers. For example, see: https://dba.stackexchange.com/questions/11506/why-are-numbers-tables-invaluable
It is a table Numbers that has one column Number with values from 1 to some large enough amount. I personally have a table of numbers with 100K rows. It is possible to generate it on the fly, but it is handy in many cases, so I have a permanent table.
SELECT
A.Col1
FROM
SourceTable
CROSS APPLY
(
SELECT SourceTable.Col1
FROM Numbers
WHERE Numbers.Number <= SourceTable.Col2
) AS A
ORDER BY Col1;

How to map the 2 different record set one by one?

Let' say I have 2 sql queries. Table A contains,
ID
--
1
1
1
2
3
4
This query,
Select distinct ID1 FROM A
gives me,
ID
--
1
2
3
4
Second one
Select ID2 FROM B
which gives me,
ID2
--
8
21
33
43
How 2 get this record set?
ID1 ID2
--- ---
1 8
2 21
3 33
4 43
You did not specify what version of sql server but if you are using sql server 2008+, one way that you can do this is by adding the row_number() to each table and then joining on the row_number():
select a.id, b.id2
from
(
select id, row_number() over(order by id) rn
from a
) a
inner join
(
select id2, row_number() over(order by id2) rn
from b
) b
on a.rn = b.rn
See SQL Fiddle with Demo
If you want to only use DISTINCT values, then you should be able to use:
select a.id, b.id2
from
(
select id, row_number() over(order by id) rn
from
(
select distinct id
from a
) a
) a
inner join
(
select id2, row_number() over(order by id2) rn
from b
) b
on a.rn = b.rn;
See SQL Fiddle with Demo
If you have a different number of rows in each table, then you might want to use a FULL OUTER JOIN:
select a.id, b.id2
from
(
select id, row_number() over(order by id) rn
from
(
select distinct id
from a
) a
) a
full outer join
(
select id2, row_number() over(order by id2) rn
from b
) b
on a.rn = b.rn;
See SQL Fiddle with Demo

problem with select

I have a table with rows with two columns
A 1
A 2
B 1
B 3
C 1
C 2
C 3
and I want to get from this only this ID(a,b or c) which has only 2 rows with value 1,2, so from this table I should get a, bacause b hasn't row with 2, and c has rows with 1 and b, but also has row with c..
What is the simplest way to get this row?
SELECT col1
FROM YourTable
GROUP BY col1
HAVING COUNT(DISTINCT col2) =2 AND MIN(col2) = 1 AND MAX(col2) = 2
Or another way extendible to more than 2 numbers
SELECT col1
FROM yourtable
GROUP BY col1
HAVING MIN(CASE
WHEN col2 IN ( 1, 2 ) THEN 1
ELSE 0
END) = 1
AND COUNT(DISTINCT col2) = 2
select t1.col1
from table as t1
left join table as t2 on (t1.col1 = t2.col1)
where t1.col2 = 1 and t2.col2 = 2;