Finding One record from table having unique PK and duplicate FK - sql

I want one record from a table having unique Primary Key and duplicate Foreign Key
Please see attached image below
alt text http://img413.imageshack.us/img413/9940/findduplicate.png
Thanks

Select fk, Count(*)
from table1
group by fk
having count(*) > 1

Primary key by definition means there will only be one, so your question appears to actually appears to be are the any rows with more than 1 child row:
select *
from table1 t
where exists (
select id from table2 t2
where t2.fkid = t.id
group by t2.id
having count(*) > 1
)

This would retrieve all unique fk and textVal values from the table:
select distinct fk, textVal from myTable

Have a look at this example.
This will find you all IDs from TABLE1 where it is duplicated in TABLE2 as a FOREIGN KEY
DECLARE #Table1 TABLE(
id INT
)
DECLARE #Table2 TABLE(
id INT,
fkid INT
)
INSERT INTO #Table1 (id) SELECT 1
INSERT INTO #Table1 (id) SELECT 2
INSERT INTO #Table1 (id) SELECT 3
INSERT INTO #Table2 (id,fkid) SELECT 1, 1
INSERT INTO #Table2 (id,fkid) SELECT 2, 2
INSERT INTO #Table2 (id,fkid) SELECT 3, 2
INSERT INTO #Table2 (id,fkid) SELECT 4, 3
INSERT INTO #Table2 (id,fkid) SELECT 5, 3
INSERT INTO #Table2 (id,fkid) SELECT 6, 3
SELECT t2.fkid
FROM #Table2 t2
GROUP BY t2.fkid
HAVING COUNT(t2.fkid) > 1

Related

SQL inserted value of a table as column of another table

Table1 Table2
Id Name Id Table1Id Value
1 Some 1 1 value1
2 Some1 2 2 value2
3 Some2 3 3 value3
4 Some3
.
.
I want to result this:
Some Some1 Some2 Some3
value1 value2 value3 NULL
When I entered value into the Table1 I want to look like the table2's column, how can I do this?
I guess I'm looking for pivot query.
Thanks for posting the additional information. Based on what you said, you're looking for a PIVOT statement that will turn each name in Table1 into a column header, containing the corresponding value from Table2.
Have a look at the following SQL, which produces the output your sample data indicates.
CREATE TABLE #Table1 (ID INT, Name varchar(5))
CREATE TABLE #Table2 (ID INT, Table1ID INT, Value varchar(6))
INSERT INTO #Table1 (ID, Name) SELECT 1, 'Some'
INSERT INTO #Table1 (ID, Name) SELECT 2, 'Some1'
INSERT INTO #Table1 (ID, Name) SELECT 3, 'Some2'
INSERT INTO #Table1 (ID, Name) SELECT 4, 'Some3'
INSERT INTO #Table2 (ID, Table1ID, Value) SELECT 1, 1, 'Value1'
INSERT INTO #Table2 (ID, Table1ID, Value) SELECT 2, 2, 'Value2'
INSERT INTO #Table2 (ID, Table1ID, Value) SELECT 3, 3, 'Value3'
-- List of values to be columns
declare #cols nvarchar(max)
select #cols = coalesce(#cols+N',', N'') + quotename(Name) from #Table1 order by ID
PRINT #Cols
declare #query varchar(MAX)
SET #query = '
SELECT *
FROM
(
SELECT T1.Name, T2.Value
FROM
#Table1 T1
INNER JOIN
#Table2 T2 ON
T1.ID = T2.Table1ID
) s
PIVOT
(
MAX(Value) FOR Name IN ('+#Cols+')
) p'
PRINT #query
EXEC (#query)
DROP TABLE #Table1
DROP TABLE #Table2

Join without foreign key for condition

I get two tables like this:
create table #table1 (data1 int)
create table #table2 (data2 int)
insert into #table1 (data1) values (1),(2),(3)
insert into #table2 (data2) values (4),(5),(6)
I want to make a query, that returns two columns like this:
data1 data2
1 4
2 5
3 6
I found one solution for this:
select t1.data1, t2.data2 from
(select row_number() over (order by data1) as [Index], data1 from #table1) as t1 inner join
(select row_number() over (order by data2) as [Index], data2 from #table2) as t2 on (t1.[Index] = t2.[Index])
Do you know other ways to join tables (any joins except cross) without keys?
EDIT: I look for solution without cursor and temporary tables.
create table table1 (data1 int)
create table table2 (data2 int)
insert into table1 (data1) values (1),(2),(3)
insert into table2 (data2) values (4),(5),(6)
create table #table1
(id int identity(1,1),
data1 int)
create table #table2
(id int identity(1,1),
data2 int)
insert into #table1 (data1) select data1 from table1
insert into #table2 (data2) select data2 from table2
create table table3
(data1 int,
data2 int)
insert into table3 (data1, data2)
select #table1.data1, #table2.data2
from #table1
inner join #table2 on #table1.id = #table2.id
what will be output in this case if i insert below values
insert into #table1 (data1) values (1),(2),(3)
insert into #table2 (data2) values (2),(3),(4)
may you need
select t1.data1, t2.data2 from t1,t2

SQL intersect with other tables, how do I ignore it?

I am trying to run a query given three tables.
DECLARE #TABLE1 TABLE (ID CHAR(2))
DECLARE #TABLE2 TABLE (ID CHAR(2))
DECLARE #TABLE3 TABLE (ID CHAR(2))
INSERT INTO #TABLE1 VALUES('1')
INSERT INTO #TABLE1 VALUES('2')
INSERT INTO #TABLE2 VALUES('1')
--NOTHING in TABLE3
I Need to get only the values that are present and ignore the null table. This doesn't work since TABLE3 has no values.
SELECT ID
FROM #TABLE1
INTERSECT
SELECT ID
FROM #TABLE2
INTERSECT
SELECT ID
FROM #TABLE3
**Result should be 1**
How do I ignore the any table if it's null but keep the other values?
Why not do a union of select distincts from each table, and then group that by ID and select count(*), and select only rows with count(*) equal to the maximum value of count(*) in the result?
It's a bit of a mess of subqueries at this point unfortunately but you should get the logic :)
Intersect is not going to work for you as you can't add conditions to it.
From what I understand you want to select all records where the ID appears in at least 2 of the tables. I am assuming that the ID is unique to each table.
The following works in MS SQL Server:
DECLARE #TABLE1 TABLE (ID CHAR(2))
DECLARE #TABLE2 TABLE (ID CHAR(2))
DECLARE #TABLE3 TABLE (ID CHAR(2))
INSERT INTO #TABLE1 VALUES('1')
INSERT INTO #TABLE1 VALUES('2')
INSERT INTO #TABLE2 VALUES('1')
--NOTHING in TABLE3
;WITH AllValues AS
(
SELECT ID
FROM #TABLE1
UNION ALL
SELECT ID
FROM #TABLE2
UNION ALL
SELECT ID
FROM #TABLE3
)
SELECT ID
FROM AllValues
GROUP BY ID
HAVING COUNT(*) > 1
Maybe... But the design of the system is extremely foreign; a real world example would help understand what you're trying to do.
Select count(*), ID FROM (
Select ID from #table1
UNION
Select ID from #table2
UNION
Select ID from #table3) Derived
Where RowNum =1
GROUP BY ID
ORder by count(*) DESC
Updated where clause was in wrong place

Full Outer Join Using Each Row Once

I'm wondering if anyone's come across a neat solution to this problem. I'm trying to select data from a couple of tables, having the records match up row by row. I'm basically after a full outer join, but there's one crucial difference. If I have four rows with a particular value in the column I'm joining on in one table, and three rows with this value in another, I only want the first three results to be joined, and the fourth to act as if there had been no match.
The reason for this is to create a reconciliation report which ensures transactions are not counted multiple times when comparing results. I can get around this issue by using a bit of grouping and some aggregate functions, but this hides some of the detail which I'd like to keep.
Below is an example to show the sort of thing I'm after, with the invalid/pseudo code in the comments illustrating how I'm thinking of this as working:
declare #t1 table (id bigint identity(1,1) primary key clustered, foreignKeyId bigint, otherData nvarchar(10))
declare #t2 table (id bigint identity(1,1) primary key clustered, foreignKeyId bigint, moreData nvarchar(10))
insert #t1 select 1, '1.1.1'
union all select 1, '1.1.2'
union all select 1, '1.1.3'
union all select 3, '1.3.1'
union all select 3, '1.3.2'
union all select 3, '1.3.3'
union all select 4, '1.4.3'
insert #t2 select 1, '2.1.1'
union all select 1, '2.1.2'
union all select 1, '2.1.3'
union all select 2, '2.2.1'
union all select 3, '2.3.1'
union all select 3, '2.3.2'
union all select 5, '2.5.1'
union all select 5, '2.5.2'
--demo of the functionality i'm hoping to acheive
--
/*
select t1.id id1
, t2.id id2
, t1.foreignKeyId fk1
, t2.foreignKeyId fk2
, t1.otherData otherData
, t2.moreData moreData
from #t1 t1
full funky join #t2 t2
on t1.foreignKeyId = t2.foreignKeyId
order by t1.id, t2.id --we'd need an order by to ensure the match could be applied in a predictable manner
*/
--
declare #funkyjoin table (id1 bigint, id2 bigint, fk1 bigint, fk2 bigint, otherData nvarchar(10), moreData nvarchar(10))
declare #id1 bigint, #id2 bigint
insert #funkyjoin (id1, fk1, otherData)
select id, foreignKeyId, otherData from #t1
while exists(select 1 from #t2)
begin
select top 1 #id2 = id from #t2 order by id
set #id1 = null
select top 1 #id1 = id1
from #funkyjoin
where fk2 is null
and fk1 in (select foreignKeyId from #t2 where id = #id2)
if #id1 is null
begin
insert #funkyjoin (id2, fk2, moreData)
select id, foreignKeyId, moreData
from #t2
where id = #id2
end
else
begin
update #funkyjoin
set id2 = #id2
, fk2 = fk1 --since we're joining on this we can just match it
, moreData = (select moreData from #t2 where id = #id2)
where id1 = #id1
end
delete from #t2 where id = #id2 --since this is only an example let's not worry about keeping our source data
end
select *
from #funkyjoin
order by coalesce(id1, id2)
I've written a similar solution for when this scenario occurs on spreadsheets previously: http://officemacros.codeplex.com/#WorksheetMergeMacro
If I understand correctly, this may be what you're after:
select *
from (
select *,
row_number() over (partition by foreignKeyId order by id) as n
from #t1
) t1
full outer join (
select *,
row_number() over (partition by foreignKeyId order by id) as n
from #t2
) t2 on t1.foreignKeyId = t2.foreignKeyId and t1.n = t2.n
The best way to use up the rows is to add a pseudo-row number (using ROW_NUMBER) and include that in the join.

Inserting the Identity of another Insert from Select?

Is This Possible?
Here is something I'm looking for, executed together:
First, it would execute the INSERT based on how many rows in the SELECT
INSERT INTO TABLE2 (xID, NAME)
SELECT xID, NAME FROM TABLE
Then getting the ##IDENTITY of each INSERTED ROW, it would create a new Insert including the same data of the first SELECT statement:
INSERT INTO TABLE3 (xID, NAME, ID)
SELECT xID, NAME, ID as Scope_IdentitY()
If not, what the best way without using cursor or while?
You have, at least, two options:
1) The OUTPUT...INTO target_table clause (SQL2005+)
2) Or you could write composable DML(SQL2008+).
Example:
DECLARE #Table2 TABLE(
ID INT IDENTITY PRIMARY KEY, --IDENTITY
xID INT NOT NULL,
NAME VARCHAR(25) NOT NULL
);
DECLARE #Table3 TABLE(
ID INT PRIMARY KEY, --No IDENTITY
xID INT NOT NULL,
NAME VARCHAR(25) NOT NULL
);
--First solution: OUTPUT ... INTO
INSERT INTO #Table2 (xID, NAME)
OUTPUT inserted.xID, inserted.NAME, inserted.ID INTO #Table3(xID, NAME, ID)
SELECT t.Col1, t.Col2
FROM (SELECT 11,'A' UNION ALL SELECT 22,'B' UNION ALL SELECT 33,'C') AS t(Col1,Col2);
--Second solution: composable DML
INSERT INTO #Table3(xID, NAME, ID)
SELECT src.xID, src.NAME, src.ID
FROM
(
INSERT INTO #Table2 (xID, NAME)
OUTPUT inserted.xID, inserted.NAME, inserted.ID
SELECT t.Col1, t.Col2
FROM (VALUES(44,'D'),(55,'E'),(66,'F')) AS t(Col1,Col2)
) src
SELECT * FROM #Table2
SELECT * FROM #Table3
INSERT INTO TABLE2 (xID, NAME)
OUTPUT
INSERTED.xID, INSERTED.NAME, INSERTED.ID
INTO TABLE3 (xID, NAME, ID)
SELECT xID, NAME FROM [TABLE]
You can declare a table variable and store the output of the rows inserted into dbo.Table2 in this variable and use the table variable as the input for table dbo.Table3.
CREATE TABLE dbo.Table1
(
xid int NOT NULL
, name varchar(30) NOT NULL
);
CREATE TABLE dbo.Table2
(
id int NOT NULL IDENTITY
, xid int NOT NULL
, name varchar(30) NOT NULL
);
CREATE TABLE dbo.Table3
(
id int NOT NULL
, xid int NOT NULL
, name varchar(30) NOT NULL
);
INSERT INTO dbo.Table1 (xid, name) VALUES
(195, 'abc'),
(242, 'def'),
(332, 'ghi');
GO
DECLARE #tempTable table
( id int
, xid int
, name varchar(30)
);
INSERT dbo.Table2
OUTPUT INSERTED.id, INSERTED.xid, INSERTED.name
INTO #tempTable
SELECT xid, name FROM dbo.Table1;
INSERT dbo.Table3 (id, xid, name)
SELECT id, xid, name FROM #tempTable;
SELECT id, xid, name FROM dbo.Table2;
SELECT id, xid, name FROM dbo.Table3;
GO
OK, based on your comments below, try this:
INSERT INTO TABLE2 (xID, NAME)
SELECT xID, NAME FROM TABLE;
INSERT INTO TABLE3 (xID, NAME, ID)
SELECT xID, NAME, ##identity
FROM TABLE2;
Assuming these table structures:
TABLE_A
-----------
X_ID
NAME
TABLE_B
----------------
TABLE_B_ID [PK]
X_ID
NAME
TABLE_C
----------------
TABLE_C_ID [PK]
X_ID
NAME
TABLE_B_ID [FK]
Then wouldn't this work (best in a transaction)?:
-- Grab data from TABLE_A and INSERT INTO TABLE_B
INSERT INTO TABLE_B (
X_ID,
NAME
)
SELECT
X_ID,
NAME
FROM
TABLE_A
-- Grab data from TABLE_B that matches the data imported from TABLE_A
-- and INSERT that data into TABLE_C (incl. the PK from TABLE_B)
INSERT INTO TABLE_C (
X_ID,
NAME,
TABLE_B_ID
)
SELECT
b.X_ID,
b.NAME,
b.TABLE_B_ID
FROM
TABLE_B b
INNER JOIN
TABLE_A a ON a.X_ID = b.X_ID