Let's say that i have a stored procedure which returns all data from two tables: A and B.
Table_A
Id Name
-----------------
1 Chuck
2 Richard
3 Arthur
Table_B
Status Nickname IdTableA
-----------------------------
1 cthulhu 1
2 Poe 3
And the query:
SELECT
a.Name, b.Status, b.Nickname
FROM
Table_A a
LEFT JOIN
Table_B b ON b.IdTableA = a.Id
If I run the stored procedure right now, it returns all the records, even when they don't have a record in table_B (as you can see, record number 2 from table_A does not exist yet -maybe tomorrow, or in a month...-). What I need to do is discard the status number 2 (which lives on table B). The problem happens when I use something like:
where b.Status = 1
or
where b.Status <> 2
Why? Because it returns only the values with Status 1. I need only discard records with status 2, but return also the records from table_A without records on table_B.
There's a way to do that?
Hope you can help me. Thanks in advance.
Does the following screenshot fulfil your requirement?
try the following:
declare #table_a table (id int, name varchar(100))
insert into #table_a select 1, 'Chuck'
union select 2, 'Richard'
union select 3, 'Arthur'
declare #table_b table (status int, nickname varchar(100), id_table_a int)
insert into #table_b
select 1, 'cthulhu', 1
union select 2, 'Poe', 3
select * from #table_a
select * from #table_b
select *
from #table_a a
left join #table_b b on a.id = b.id_table_a
where isnull(status,'') <> 2
Related
My Query is like
Select * From T Where ID=1 AND ID=2 AND ID=3 And So On
These ID From Another Result Set Like Select ID From T2
If I Apply IN Operation SELECT * From T Where ID IN(1,2,3) It shows if there is any entry for 1 or 2 or 3 But in my requirement their should be ID 1 AND 2 AND 3
means ID IS 1,2,3 if 2 is not there result should be empty
how to apply this query.
1,2,3 is from another result set so I can't use directly and means I can't use where ID=1 AND ID=2 AND So On
Try this
SELECT * From T Where ID IN(Select ID From T2 where ID is not NULL)
The condition is applied to each row. Each row has only one ID. And so that ID can't be equal to 1 and equal to 2 and equal to 3. You need to use OR.
where ID=1 OR ID=2 OR ID=3
Your condition Where ID=1 AND ID=2 AND ID=3 is never going to fetch you any record, as ID column of each row can hold only 1 value, which can be either 1 or 2 or 3 but not all.
Ideally your query should be like
Select * From T Where ID=1 OR ID=2 OR ID=3
Above query is equivalent to
SELECT * From T Where ID IN(1,2,3)
If you want to fetch the records where id exists in another table, there are multiple ways like
1- EXISTS
Select * From T t1
Where exists
(
select 1 from t2 as t2 where t2.id=t1.id
)
2- Using IN
Select * From T t1
where id in
(
select id from t2
)
DECLARE #c2 INT
SELECT DISTINCT #c2 = COUNT(id) FROM T2
DECLARE #c1 INT
SELECT DISTINCT #c1 = COUNT(T.id) FROM T JOIN T2 on T.id=T2.id
SELECT * FROM T WHERE #c1 = #c2
I have two tables like below.
table 1
id rem
1 2
2 1
table 2
id value
1 abc
1 xyz
1 mno
2 mnk
2 mjd
EDIT:
#output
id value
1 abc
1 xyz
2 mnk
What i want to do is select top 2 rows of table2 with id one as rem value is 2 for id 1 and top 1 row with id 2 as its rem value is 1 and so on. I am using MS sqlserver 2012 My whole scenario is more complex than this. Please help.
Thank you.
EDIT : I know that i should have given what i have done and how i am doing it but for this particular part i don't have idea for starting. I could do this by using while loop for each unique id but i want to do it in one go if possible.
First, SQL tables represent unordered sets. There is no specification of which values you get, unless you include an order by.
For this purpose, I would go with row_number():
select t2.*
from table1 t1 join
(select t2.*,
row_number() over (partition by id order by id) as seqnum
from table2 t2
) t2
on t1.id = t2.id and t2.seqnum <= t1.rem;
Note: The order by id in the windows clause should be based on which rows you want. If you don't care which rows, then order by id or order by (select null) is fine.
Try This:
DECLARE #tbl1 TABLE (id INT, rem INT)
INSERT INTO #tbl1 VALUES (1, 2), (2, 1)
DECLARE #tbl2 TABLE (id INT, value VARCHAR(10))
INSERT INTO #tbl2 VALUES (1, 'abc'), (1, 'xyz'),
(1, 'mno'), (2, 'mnk'), (2, 'mjd')
SELECT * FROM #tbl1 -- your table 1
SELECT * FROM #tbl2 -- your table 2
SELECT id,value,rem FROM ( SELECT ROW_NUMBER() OVER (PARTITION BY T.ID ORDER BY T.ID) rowid,
T.id,T.value,F.rem FROM #tbl2 T LEFT JOIN #tbl1 F ON T.id = F.id ) A WHERE rowid = 1
-- your required output
Hope it helps.
I have two tables:
Table1
ID TYPE
1 ABC1
2 ABC2
3 ABC3
Table2
ID Data
1 100
1 101
2 10
2 90
And I want the results to look like this:
ID Data1 Data2
1 100 101
2 10 90
But I'm having a total mare with my attempts at creating the pivot. So far I have:
With Inital_Data As (
Select
A.ID,
B.Data As Data1,
B.Data As Data2
From
Table1 A join
Table2 B on
A.ID = B.ID
)
Select *
From
Initial_Data
PIVOT
(Max(ID) FOR Data IN (Data1,Data2)) p
I know this is rubbish but so far even the logic of what I'm trying to achieve is escaping me, let alone the syntax! Can anyone give me a guiding hand?
Pivot with more than one column needs some tricks, I prefer the XML concatenation. First I take all values for each ID in only one XML, then you can take these values one by one:
Just paste this into an empty query window and execute. Adapt for your needs
EDIT: Includes column Type from TABLE1 as Caption for ID...
DECLARE #Table1 TABLE(ID INT,[TYPE] VARCHAR(10));
INSERT INTO #Table1 VALUES
(1,'ABC1')
,(2,'ABC2')
,(3,'ABC3');
DECLARE #Table2 TABLE(ID INT,DATA INT);
INSERT INTO #Table2 VALUES
(1,100)
,(1,101)
,(2,10)
,(2,90);
WITH DistinctIDs AS
(
SELECT DISTINCT tbl2.ID,tbl1.[TYPE]
FROM #Table2 AS tbl2
INNER JOIN #Table1 AS tbl1 ON tbl1.ID=tbl2.ID
)
SELECT ID,[TYPE]
,concatXML.x.value('/root[1]/item[1]/#data','int') AS Data1
,concatXML.x.value('/root[1]/item[2]/#data','int') AS Data2
FROM DistinctIDs AS dIDs
CROSS APPLY
(
SELECT ID AS [#id],DATA AS [#data]
FROM #Table2 AS tbl WHERE tbl.ID=dIDs.ID
FOR XML PATH('item'), ROOT('root'),TYPE
) AS concatXML(x)
I have following tow tables
create table #temp(id int,rid int)
insert into #temp
select 1,1
union all
select 2,1
union all
select 3,1
select * from #temp
drop table #temp1
create table #temp1(id int, nid int,PRIMARY KEY CLUSTERED
(
id asc,nid asc
))
insert into #temp1
select 1,10
union all
select 2,10
union all
select 2,11
union all
select 3,10
Following are the both result sets:
id rid
1 1
2 1
3 1
id nid
1 10
2 10
2 11
3 10
I want to update #temp1 table with value from rid field of #temp table by matching id field from both tables. See following query:
select a.*
from #temp1 a inner join #temp b
on a.id = b.id
where a.id <> b.rid
It returns:
id nid
2 10
2 11
3 10
I want to update id with following query:
update a
set a.id = b.rid
-- select a.*
from #temp1 a inner join #temp b
on a.id = b.id
where a.id <> b.rid
But it returns
primary key violation error because of primary key in table #temp1.
I would like to delete the value if it is already exist if not then I would like to update
for example
id nid
1 10
2 10-- want to update but not able to this bcoz it violates primary key so delete this row.
2 11-- able to update this row but other 2 rows causing an issue.
3 10-- want to update but not able to this bcoz it violates primary key so delete this row.
Please suggest other ways to do this.
Because You are Violating the Primary Key Constraints
Check Below Tables
select B.*
from #temp1 a inner join #temp b
on a.id = b.id
where a.id <> b.rid
id rid
2 1
2 1
3 1
select * from #temp1
id nid
1 10
2 10
2 11
3 10
You are setting ID of above first table using join from #temp which already in #temp1
You Are attempt to Update Values which are already in #temp1 where id=2,2,3
select *
from #temp1 a inner join #temp b
on a.id = b.id
where a.id <> b.rid
You would be updating two id 2 records to the same value. You cannot do this, period. There is no other method to fix this except to drop the PK which I would suggest would be bad idea.
It is possible you need some further definition in your pdate to specify which of multiple records you want to update or you may need to delete the record which might end up as a duplicate before you do the update. Not knowing the business rules for what you are actually trying to accomplish or what your data means, it is impossiblet say what you can do to solve your problem. This ia case where the solution is dependant on the meaning and of course we have no meaning here.
I have an adjacent list hierarchy model that makes up a topic structure
ID Parent_Id Topic_Name
1 Null Topic 1
2 Null Topic 2
3 2 Topic 3
4 3 Topic 4
5 2 Topic 5
6 Null Topic 6
This forms part of an application which I cant change - the topics dont have multiple parents so unfortunatly I can't move to a nested sets - although if this was an interim step in the process - this would be fine as long as it went back to adjacent list hierarchy model
I want to specify a topic id and then copy it to a new topic id and retain the levels / structure underneath
So in my example I could specify topic topic_id 2 and it would create
ID Parent_Id Topic_Name
7 Null Topic 2
8 7 Topic 3
9 8 Topic 4
10 7 Topic 5
Auto numbering is taken care of for the ID so no need to construct that, but obviously the parent id needs to be retained
How can I achieve the above? would I need to flatten the data and do 3 seperate inserts logging the id after each insert?
You can use a recursive CTE to get the rows to insert.
If you use merge to add the rows you can use output to capture a mapping between the generated ID and the old ID which can be used to update the column Parent_ID for the inserted rows.
-- ID for topic to copy
declare #ID int;
set #ID = 2;
-- Table to hold the inserted rows
declare #T table
(
New_ID int,
Old_ID int,
Old_ParentID int
);
-- Add rows from recursive CTE using merge
with C as
(
select T.ID, T.Parent_Id, T.Topic_Name
from YourTable as T
where T.ID = #ID
union all
select T.ID, T.Parent_Id, T.Topic_Name
from YourTable as T
inner join C
on C.ID = T.Parent_Id
)
merge YourTable
using C
on 0 = 1
when not matched then
insert (Topic_Name) values (C.Topic_Name)
output inserted.ID,
C.ID,
C.Parent_Id
into #T(New_ID, Old_ID, Old_ParentID);
-- Update Parent_Id for the new rows
update Y set
Parent_Id = T2.New_ID
from #T as T1
inner join #T as T2
on T1.Old_ParentID = T2.Old_ID
inner join YourTable as Y
on T1.New_ID = Y.ID;
SE-Data
Working example. Works in theory but probably not robust for high transaction volumes or fast enough for big tables.
--- sample table
create table tbl (
id int identity primary key,
parent_id int references tbl(id),
topic_name varchar(100));
insert tbl values
( Null, 'Topic 1'),
( 1, ' Topic 2'),
( 2 , ' Topic 3'),
( 3 , ' Topic 4'),
( 2 , ' Topic 5'),
( Null, ' Topic 6'),
( 4, ' Topic 4-3'),
( 7, ' Topic 5-4')
;
--- script to duplicate a hierarchy branch
declare #inserttbl table (
id int,
parent_id int,
topic_name varchar(100));
;with cte as (
select id, parent_id, topic_name
from tbl
where id=2 -- or parameter
union all
select t.id, t.parent_id, t.topic_name
from tbl t
join cte c on t.parent_id=c.id
), cte2 as (
select *,rn=row_number() over (order by id)
from cte
), cte3 as (
select rec.*, par.rn as parent_rn
from cte2 rec
left join cte2 par on par.id=rec.parent_id
)
insert #inserttbl
select cte3.rn,
case when cte3.rn=1 then cte3.parent_id
else cte3.parent_rn end,
topic_name
from cte3;
insert tbl(topic_name)
select topic_name from #inserttbl order by id;
declare #delta int=scope_identity()-##rowcount;
update t
set parent_id = i.parent_id + case when i.id=1 then 0
else #delta end
from tbl t
join #inserttbl i on t.id - #delta = i.id;
--- check results
select * from tbl;