Creating a cross-tab in SQL Server - sql

I have two equal sets (say, for instance, [1,2,3]) and want to create a table with all possible combinations so I can fill existing counts later in a new column instead of just counting and doing a GROUP BY.
What I have tried:
CREATE TABLE table1
(
Var1 varchar(254),
Var2 varchar(254)
)
INSERT INTO table1 (Var1) VALUES ('1')
INSERT INTO table1 (Var1) VALUES ('2')
INSERT INTO table1 (Var1) VALUES ('3')
INSERT INTO table1 (Var2) VALUES ('1')
INSERT INTO table1 (Var2) VALUES ('2')
INSERT INTO table1 (Var2) VALUES ('3')
This, however, results in:
Var1
Var2
1
NULL
2
NULL
3
NULL
NULL
1
NULL
2
NULL
3
When what I want is something like this:
Var1
Var2
1
1
1
2
1
3
2
1
2
2
2
3
3
1
3
2
3
3
How can I do this without having to insert each combination manually?

Using your example table and values:
select a.var1, b.Var2
from table1 a, table1 b
where a.var1 is not null and b.Var2 is not null
order by a.var1, b.Var2
NOTE: you can do this with just a single column
CREATE TABLE table1(Var1 varchar(254))
INSERT INTO table1 (Var1) values ('1')
INSERT INTO table1 (Var1) values ('2')
INSERT INTO table1 (Var1) values ('3')
select a.var1, b.Var1 var2
from table1 a, table1 b
order by a.var1, b.Var1

You can do this with cross apply.
select v1.var1, v2.var2
from table1 v1
cross apply table1 v2
order by v1.var1

Related

Insert columns into new table where one of the columns doesn't allow null values

I am attempting to insert 50 rows at a time from one table into another, however I am unable to bypass the 'Not Null' column in the table I am attempting to INSERT INTO.
Please note I am not able to alter that column so it accepts nulls.
I have 2 tables (table 1 and table 2). I am inserting 2 columns from table 1 into table 2 (table 2 is currently empty). The problem is that table 2 has a third column which cannot have null values.
This is what I have so far.
-- Checking what exists in Table 1 that doesn't exist in Table 2 before inserting
IF EXISTS (SELECT T1.Column1, T1.Column2
FROM Table_1 T1
LEFT JOIN Table_2 T2 on T1.Column1=T2.Column1
WHERE T2.Column1 IS NULL)
BEGIN
INSERT INTO Table_2 (Column1, Column2)
SELECT TOP(50) Column1, Column2
FROM Table_1
ORDER BY Column1
SELECT ##ROWCOUNT
END
IF ##ROWCOUNT < 50
(
SELECT *
FROM Table_2
)
BEGIN
UPDATE Table_2
SET Column3 = 0
END
The problem is that Column 3 in Table 2 does not exist in Table 1 so there is nothing I can insert into Table 2 from Table 1 to populate the column that does not allow nulls in Table 2.
You can select a constant
INSERT INTO Table_2 (Column1, Column2, Column3)
SELECT top(50) Column1, Column2, 0
FROM Table_1
ORDER BY Column1

Select a new column based on values of two column from two tables with null if no data is present

How to select a new column based on values of two column from two tables with null if no data is present.
I have two tables
table1 with column1 and table2 with column2. I need to select data from both these columns in column3 (column3 would be a part of table1) in a way that:
column1 column2 column3
------- ------- -------
1 2 null
2 3 present
3 present
4 null
If the value of column2 is present in column1
=> I need to be able to assign a string(lets say "present") in column3
else the value in column3 should be null
At present I am using join but I wasnt able to assign the null part to column3
Thanks in advance.
create table table1(column1 int);
create table table2(column2 int);
insert into table1 values(1);
insert into table1 values(2);
insert into table1 values(3);
insert into table1 values(4);
insert into table2 values(2);
insert into table2 values(3);
Query:
select column1, (case when column2 is not null then 'Present' else Null end) Column3
from table1 left join table2 on column1=column2
Output:
column1
Column3
1
null
2
Present
3
Present
4
null
db<>fiddle here
if col1 and col2 don't have duplicate value, you can use:
select t1.col1 , case when t2.col2 is not null then 'present' else null end
from table1 t1
left join table2 t2
on t1.col1 = t2.col2

SQL: a precise flip of row data into column

I am wondering if there is an elegant refactoring for the bottom 3 'create table' segments below, which retrieves the same result.
I am hoping to generalise for a far bigger dataset.
Many thanks in advance.
// These top two lines for viewing in SQLite:
.mode column
.headers on
Create table Data_Table (
Other varchar(255),
Id varchar(255),
Value int );
INSERT INTO Data_Table (other, id, value )
VALUES ('x','a', 1);
INSERT INTO Data_Table (other,id, value )
VALUES ('y','a', 2);
INSERT INTO Data_Table (other,id, value )
VALUES ('x','b', 2);
INSERT INTO Data_Table (other,id, value )
VALUES ('y','b', 3);
Create table SubTable_A as
select t1.other as other, t1.value as a
from Data_table as t1
where t1.id = 'a';
Create table SubTable_B as
select t2.value as b
from Data_table as t2
where t2.id = 'b';
Create table Soln_Table as
select t1.*, t2.*
from SubTable_A as t1, SubTable_B as t2
where t1.rowid = t2.rowid;
Bottom line, we now have this data set
other a b
---------- ---------- ----------
x 1 2
y 2 3
You can use conditional aggregation:
select t.other,
max(case when t.id = 'a' then value end) as a,
max(case when t.id = 'b' then value end) as b
from Data_Table t
group by t.other;

Select values from a table that are not in a list SQL

If I type:
SELECT name FROM table WHERE name NOT IN ('Test1','Test2','Test3');
I can get the entries from the table that are not in the list. I want to do the opposite: Get the values from the list that are not in the table. For example, if table has a column named name that has the values 'Test1' and 'Test3' I want to compare that to ('Test1','Test2','Test3') and return Test2. Or as another example, if the table is empty, then return everything in the list: Test1, Test2, and Test3.
Is there a way to do this WITHOUT creating a new table with all of the values in the list?
Depending on how many values you have, you could do a few unions.
See: http://www.sqlfiddle.com/#!5/0e42f/1
select * from (
select 'Test 1' thename union
select 'Test 2' union
select 'Test 3'
)
where thename not in (select name from foo)
I usually use SELECT 'FOO' AS COL UNION SELECT 'BAR' etc and then use the standard idiom of left joining and checking for NULL to find missing elements.
CREATE TABLE #YourTable(
name nvarchar(50)
)
insert into #YourTable (name) values ('Test1'), ('Test3')
-- ALL
select * from #YourTable
--MISSING
select t1.* from (
select 'Test1' testName
union select 'Test2'
union select 'Test3') as t1
left outer join #YourTable yt on t1.testName = yt.name
where yt.name is null
DROP TABLE #YourTable
Gives output
name
--------------------------------------------------
Test1
Test3
(2 row(s) affected)
testName
--------
Test2
(1 row(s) affected)
Select a.value from (
SELECT 'testvalue' value UNION
SELECT 'testvalue2' value UNION
SELECT 'testvalue3' value UNION
SELECT 'testvalue4' value UNION
) a
left outer join othertable b
on a.value=b.value
where b.value is null
This is perfect for my problem without temp table#
Assuming "othertable" holds the table in question...
select a.value from
(select 'test1' value
union
select 'test2' value
union
select 'test3' value) a
left outer join othertable b
on a.value=b.value
where b.value is null
In SQL server, the below query works well.
SELECT v.val FROM (VALUES
('A'),
('B'),
('C'),
('D'),
('E')
) v (val)
LEFT JOIN dbo.TABLE_NAME t ON t.COLUMN_NAME = v.val
WHERE t.COLUMN_NAME IS NULL;
Can find the below output:
val
-------
A
B
C
D

How to create a view which merges two tables?

I have two tables which have the exact same structure. Both tables can store the same data with different primary keys (autoincremented integers). Therefore, there is a third table which lists which two primary keys list the same data. However, there also exist rows which don't exist in the other. Therefore, a simple join won't work since you will have two rows with the same primary key but different data. Therefore, is there a way of reassigning primary keys to unused values in the view?
Table1
ID name
1 Adam
2 Mark
3 David
4 Jeremy
Table2
ID name
1 Jessica
2 Jeremy
3 David
4 Mark
Table3
T1ID T2ID
2 4
3 3
4 2
I am looking for a result table like the following:
Result
ID name
1 Adam
2 Mark
3 David
4 Jeremy
5 Jessica
The real heart of the question is how i can assign the temporary fake id of 5 to Jessica and not just some random number. The rule I want for the ids is that if the row exists in the first table, then use its own id. Otherwise, use the next id that an insert statement would have generated (the column is on autoincrement).
Answer to edited question
select id, name from table1
union all
select X.offset + row_number() over (order by id), name
from (select MAX(id) offset from table1) X
cross join table2
where not exists (select * from table3 where t2id = table2.id)
The MAX(id) is used to "predict" the next identity that would occur if you merged the data from the 2nd table into the first. If Table3.T2ID exists at all, it means that it is already included in table1.
Using the test data below
create table table1 (id int identity, name varchar(10))
insert table1 select 'Adam' union all
select 'Mark' union all
select 'David' union all
select 'Jeremy'
create table table2 (id int identity, name varchar(10))
insert table2 select 'Jessica' union all
select 'Jeremy' union all
select 'David' union all
select 'Mark'
create table table3 (t1id int, t2id int)
insert table3 select 2,4 union all
select 3,3 union all
select 4,2
Answer to original question below
So the 3rd table is the one you want to build (a view instead of a table)?
select newid=row_number() over (order by pk_id), *
from
(
select a.*
from tblfirst a
UNION ALL
select b.*
from tblsecond b
) X
The data will contain a unique newid value for each record, whether from first or second table. Change pk_id to your primary key column name.
Assuming you have below data, as I understand reading your question:
Table: T1
ID name
--------
1 a
2 b
3 c
Table: T2
ID name
--------
2 b
3 c
4 d
Table: Rel
ID1 ID2
--------
2 2
3 3
T1 has some data which is not in T2 and vice versa.
Following query will give all data unioned
SELECT ROW_NUMBER() OVER (order by name) ID, Col
from
(
SELECT ISNULL(T1.name,'') name
FROM T1 t1 LEFT JOIN Rel TR ON TR.ID1 = T1.ID
union
SELECT ISNULL(T2.name,'') name
FROM T2 t2 LEFT JOIN Rel TR ON TR.ID2 = T2.ID
) T
If I understand you correct, following might work
Select everything from your first table
Select everything from your second table that is not linked to your third table
Combine the results
Test data
DECLARE #Table1 TABLE (ID INTEGER IDENTITY(1, 1), Value VARCHAR(32))
DECLARE #Table2 TABLE (ID INTEGER IDENTITY(1, 1), Value VARCHAR(32))
DECLARE #Table3 TABLE (T1ID INTEGER, T2ID INTEGER)
INSERT INTO #Table1 VALUES ('Adam')
INSERT INTO #Table1 VALUES ('Mark')
INSERT INTO #Table1 VALUES ('David')
INSERT INTO #Table1 VALUES ('Jeremy')
INSERT INTO #Table2 VALUES ('Jessica')
INSERT INTO #Table2 VALUES ('Jeremy')
INSERT INTO #Table2 VALUES ('David')
INSERT INTO #Table2 VALUES ('Mark')
INSERT INTO #Table3 VALUES (2, 4)
INSERT INTO #Table3 VALUES (3, 3)
INSERT INTO #Table3 VALUES (4, 2)
SQL Statement
SELECT ROW_NUMBER() OVER (ORDER BY ID), t1.Value
FROM #Table1 t1
UNION ALL
SELECT ROW_NUMBER() OVER (ORDER BY ID) + offset, t2.Value
FROM #Table2 t2
LEFT OUTER JOIN #Table3 t3 ON t3.T2ID = t2.ID
CROSS APPLY (
SELECT Offset = COUNT(*)
FROM #Table1
) offset
WHERE t3.T2ID IS NULL