Is it possible to delete all records from table A which exist in table B if there are no primary or foreign keys? Similar to this answer:
DELETE a
FROM #A a
WHERE EXISTS (SELECT a.* INTERSECT SELECT * FROM #B)
In DB2 each SELECT has to have a FROM clause and FROM sysibm.sysdummy1 does not work here.
Personally, I'd probably just use a multi-step process...
create table tmp as (
select * from #A
EXCEPT
select * from #B
);
delete from #A;
insert into #A
select * from tmp;
Anything else I can think of seems to require an explicit list of column names.
delete
from #A a
where exists (select *
from #B b
where a.Fld1 = b.Fld1
and a.Fld2 = b.Fld2
<...>
);
Also considered a quantified predicate and the IN predicate...something like
delete
from #A a
where (a.*) in (select * from #B);
delete
from #A a
where (a.*) <> ALL (select * from #B);
But I don't believe (a.*) is considered a row-value-expression and regardless the documentation for both say that
SELECT * is not allowed in the outermost select lists of the fullselect
Lastly, note that all of these are going to have problems if there are any NULL columns.
try somthing like this :
delete from #A a
where exists
(
select * from #b b
where
(b.field1=a.field1 or b.field1 is null and a.field1 is null) and
(b.field2=a.field2 or b.field2 is null and a.field2 is null) and
(b.field3=a.field3 or b.field3 is null and a.field3 is null)
)
Related
I have the below query that get results from more than one select.
Now I want these to be in a temp table.
Is there any way to insert these into a temp table without creating the table?
I know how to do that for select
Select * into #s --like that
However how to do that one more than one select?
SELECT Ori.[GeoBoundaryAssId], Ori.[FromGeoBoundaryId], Ori.Sort
From [GeoBoundaryAss] As Ori where Ori.[FromGeoBoundaryId] = (select distinct [FromGeoBoundaryId] from inserted )
Union
SELECT I.[GeoBoundaryAssId], I.[FromGeoBoundaryId], I.Sort
From [inserted] I ;
Add INTO after the first SELECT.
SELECT Ori.[GeoBoundaryAssId], Ori.[FromGeoBoundaryId], Ori.Sort
INTO #s
From [GeoBoundaryAss] As Ori where Ori.[FromGeoBoundaryId] = (select distinct [FromGeoBoundaryId] from inserted )
Union
SELECT I.[GeoBoundaryAssId], I.[FromGeoBoundaryId], I.Sort
From [inserted] I ;
Try this,
INSERT INTO #s ([GeoBoundaryAssId], [FromGeoBoundaryId], Sort)
(
SELECT Ori.[GeoBoundaryAssId], Ori.[FromGeoBoundaryId], Ori.Sort
FROM [GeoBoundaryAss] AS Ori WHERE Ori.[FromGeoBoundaryId] in (SELECT DISTINCT [FromGeoBoundaryId] FROM inserted )
UNION
SELECT I.[GeoBoundaryAssId], I.[FromGeoBoundaryId], I.Sort
FROM [inserted] I
)
Suppose that I have this query:
select *
from myTable
where myTable.myCol in (1,2,3)
I would like to do that:
with allowed_values as (1,2,3)
select *
from myTable
where myTable.myCol in allowed_values
It gives me a Syntax Error in the first row, can you help me fixing it?
The closest I can think to your syntax:
WITH allowed_values (id) AS
( VALUES
(1), (2), (3)
)
SELECT *
FROM myTable
WHERE id IN
(TABLE allowed_values) ;
Tested in SQL-Fiddle
Close to what you probably had in mind:
WITH allowed_values AS (SELECT '{1,2,3}'::int[] AS arr)
SELECT *
FROM my_table
,allowed_values -- cross join with a single row
WHERE my_col = ANY (arr);
Better:
WITH allowed_values (my_col) AS (VALUES (1), (2), (3))
SELECT *
FROM allowed_values
JOIN my_table USING (my_col)
But really, you can just simplify:
SELECT *
FROM (VALUES (1), (2), (3)) AS allowed_values (my_col)
JOIN my_table USING (my_col);
Try
with allowed_values as (select 1 as tst union all select 2 union all select 3)
select * from myTable a
inner join c1 b ON (b.tst = a.myCol)
The simplest way forward is to correct your common table expression, then use it in a subselect.
with allowed_values as (
select 1 id
union all
select 2
union all
select 3
)
select * from myTable
where myTable.id in (select id from allowed_values)
I have written a very simple CTE expression that retrieves a list of all groups of which a user is a member.
The rules goes like this, a user can be in multiple groups, and groups can be nested so that a group can be a member of another group, and furthermore, groups can be mutual member of another, so Group A is a member of Group B and Group B is also a member of Group A.
My CTE goes like this and obviously it yields infinite recursion:
;WITH GetMembershipInfo(entityId) AS( -- entity can be a user or group
SELECT k.ID as entityId FROM entities k WHERE k.id = #userId
UNION ALL
SELECT k.id FROM entities k
JOIN Xrelationships kc on kc.entityId = k.entityId
JOIN GetMembershipInfo m on m.entityId = kc.ChildID
)
I can't find an easy solution to back-track those groups that I have already recorded.
I was thinking of using an additional varchar parameter in the CTE to record a list of all groups that I have visited, but using varchar is just too crude, isn't it?
Is there a better way?
You need to accumulate a sentinel string within your recursion. In the following example I have a circular relationship from A,B,C,D, and then back to A, and I avoid a loop with the sentinel string:
DECLARE #MyTable TABLE(Parent CHAR(1), Child CHAR(1));
INSERT #MyTable VALUES('A', 'B');
INSERT #MyTable VALUES('B', 'C');
INSERT #MyTable VALUES('C', 'D');
INSERT #MyTable VALUES('D', 'A');
; WITH CTE (Parent, Child, Sentinel) AS (
SELECT Parent, Child, Sentinel = CAST(Parent AS VARCHAR(MAX))
FROM #MyTable
WHERE Parent = 'A'
UNION ALL
SELECT CTE.Child, t.Child, Sentinel + '|' + CTE.Child
FROM CTE
JOIN #MyTable t ON t.Parent = CTE.Child
WHERE CHARINDEX(CTE.Child,Sentinel)=0
)
SELECT * FROM CTE;
Result:
Parent Child Sentinel
------ ----- --------
A B A
B C A|B
C D A|B|C
D A A|B|C|D
Instead of a sentinel string, use a sentinel table variable. Function will catch circular reference no matter how many hops the circle is, no issues with maximum length of nvarchar(max), easily modified for different data types or even multipart keys, and you can assign the function to a check constraint.
CREATE FUNCTION [dbo].[AccountsCircular] (#AccountID UNIQUEIDENTIFIER)
RETURNS BIT
AS
BEGIN
DECLARE #NextAccountID UNIQUEIDENTIFIER = NULL;
DECLARE #Sentinel TABLE
(
ID UNIQUEIDENTIFIER
)
INSERT INTO #Sentinel
( [ID] )
VALUES ( #AccountID )
SET #NextAccountID = #AccountID;
WHILE #NextAccountID IS NOT NULL
BEGIN
SELECT #NextAccountID = [ParentAccountID]
FROM [dbo].[Accounts]
WHERE [AccountID] = #NextAccountID;
IF EXISTS(SELECT 1 FROM #Sentinel WHERE ID = #NextAccountID)
RETURN 1;
INSERT INTO #Sentinel
( [ID] )
VALUES ( #NextAccountID )
END
RETURN 0;
END
If you run the following sample code in SQL Server, you'll notice that newid() materializes after the join whereas row_number() materializes before the join. Does anyone understand this and if there's a way to work around it?
declare #a table ( num varchar(10) )
insert into #a values ('dan')
insert into #a values ('dan')
insert into #a values ('fran')
insert into #a values ('fran')
select *
from #a T
inner join
(select num, newid() id
from #a
group by num) T1 on T1.num = T.num
select *
from #a T
inner join
(select num, row_number() over (order by num) id
from #a
group by num) T1 on T1.num = T.num
i had a similar problem and found out that the "inner join" was the problem. i was able to use "left joins" ...
Not sure I see what the problem is here. Materialize the subquery T1 first:
SELECT num, ROW_NUMBER() OVER (ORDER BY num)
FROM #a
GROUP BY num;
You get two rows:
dan 1
fran 2
Now join that against a on num = num, you get 4 rows, 2 for each distinct value. What is your actual goal here? Perhaps you should be applying ROW_NUMBER() outside?
The order of materialization is up to the optimizer. You'll find that other built-ins (RAND(), GETDATE() etc.) have similarly inconsistent materialization behavior. Not much you can do about it, and not much chance they're going to "fix" it.
EDIT
New code sample. Write the contents of #a to a #temp table to "materialize" the NEWID() assignment per unique num value.
SELECT num, id = NEWID()
INTO #foo FROM #a GROUP BY num;
SELECT a.num, f.id
FROM #a AS a
INNER JOIN #foo AS f
ON a.num = f.num;
DROP TABLE #foo;
in my stored procedure I have a table variable contains rows ID. The are 2 scenarios - that table variable is empty and not.
declare #IDTable as table
(
number NUMERIC(18,0)
)
In the main query, I join that table:
inner join #IDTable tab on (tab.number = csr.id)
BUT:
as we know how inner join works, I need that my query returns some rows:
when #IDTable is empty
OR
return ONLY rows that exist in
#IDTable
I tried also with LEFT join but it doesn't work. Any ideas how to solve it ?
If `#IDTable' is empty then what rows do you return? Do you just ignore the Join on to the table?
I'm not sure I get what you're trying to do but this might be easier.
if (Select Count(*) From #IDTable) == 0
begin
-- do a SELECT that doesn't join on to the #IDTable
end
else
begin
-- do a SELECT that joins on to #IDTable
end
It is not optimal, but it works:
declare #z table
(
id int
)
--insert #z values(2)
select * from somTable n
left join #z z on (z.id = n.id)
where NOT exists(select 1 from #z) or (z.id is not null)