INSERT multiple rows based on SELECT statement - sql

I am using SQL Server 2008 and with the help of other threads I have been able to write the following:
insert into fml0grant (auto_key, roleid)
select fml0.auto_key, 20
from fml0
left join fml0grant on fml0.auto_key = fml0grant.auto_key
where fml0.dwgname <> ''
and fml0grant.roleid is null
However what I need to do is insert multiple rows for each record found in the where clause. So when the where clause gets a result I need to insert:
fml0.auto_key, 20
fml0.auto_key, 508
fml0.auto_key, 10
Is there any way to combine all three inserts into one statement as after the first in my query the NULL in the WHERE clause is no longer true.

You can use CROSS JOIN as the below.
insert into fml0grant (auto_key, roleid)
select fml0.auto_key, V.Id
from fml0
left join fml0grant on fml0.auto_key = fml0grant.auto_key
CROSS JOIN (VALUES (20),(508),(10)) V (Id)
where fml0.dwgname <> ''
and fml0grant.roleid is null

Related

Rewrite query without using temp table

I have a query that is using a temp table to insert some data then another select from to extract distinct results. That query by it self was fine but now with entity-framework it is causing all kinds of unexpected errors at the wrong time.
Is there any way I can rewrite the query not to use a temp table? When this is converted into a stored procedure and in entity framework the result set is of type int which throws an error:
Could not find an implementation of the query pattern Select not found.
Here is the query
Drop Table IF EXISTS #Temp
SELECT
a.ReceiverID,
a.AntennaID,
a.AntennaName into #Temp
FROM RFIDReceiverAntenna a
full join Station b ON (a.ReceiverID = b.ReceiverID) and (a.AntennaID = b.AntennaID)
where (a.ReceiverID is NULL or b.ReceiverID is NULL)
and (a.AntennaID IS NULL or b.antennaID is NULL)
select distinct r.ReceiverID, r.ReceiverName, r.receiverdescription
from RFIDReceiver r
inner join #Temp t on r.ReceiverID = t.ReceiverID;
No need for anything fancy, you can just replace the reference to #temp with an inner sub-query containing the query that generates #temp e.g.
select distinct r.ReceiverID, r.ReceiverName, r.receiverdescription
from RFIDReceiver r
inner join (
select
a.ReceiverID,
a.AntennaID,
a.AntennaName
from RFIDReceiverAntenna a
full join Station b ON (a.ReceiverID = b.ReceiverID) and (a.AntennaID = b.AntennaID)
where (a.ReceiverID is NULL or b.ReceiverID is NULL)
and (a.AntennaID IS NULL or b.antennaID is NULL)
) t on r.ReceiverID = t.ReceiverID;
PS: I haven't made any effort to improve the query overall like Gordon has but do consider his suggestions.
First, a full join makes no sense in the first query. You are selecting only columns from the first table, so you need that.
Second, you can use a CTE.
Third, you should be able to get rid of the SELECT DISTINCT by using an EXISTS condition.
I would suggest:
WITH ra AS (
SELECT ra.*
FROM RFIDReceiverAntenna ra
Station s
ON s.ReceiverID = ra.ReceiverID AND
s.AntennaID = ra.AntennaID)
WHERE s.ReceiverID is NULL
)
SELECT r.ReceiverID, r.ReceiverName, r.receiverdescription
FROM RFIDReceiver r
WHERE EXISTS (SELECT 1
FROM ra
WHERE r.ReceiverID = ra.ReceiverID
);
You can use CTE instead of the temp table:
WITH
CTE
AS
(
SELECT
a.ReceiverID,
a.AntennaID,
a.AntennaName
FROM
RFIDReceiverAntenna a
full join Station b
ON (a.ReceiverID = b.ReceiverID)
and (a.AntennaID = b.AntennaID)
where
(a.ReceiverID is NULL or b.ReceiverID is NULL)
and (a.AntennaID IS NULL or b.antennaID is NULL)
)
select distinct
r.ReceiverID, r.ReceiverName, r.receiverdescription
from
RFIDReceiver r
inner join CTE t on r.ReceiverID = t.ReceiverID
;
This query will return the same results as your original query with the temp table, but its performance may be quite different; not necessarily slower, it can be faster. Just something that you should be aware about.

how to properly merge these 2 query into one update?

This currently work but I would like to change the update statement to include the action of the insert below it, is it posssible?
UPDATE cas
SET [Locked] = CASE WHEN cas.Locked <> #TargetState AND cas.LastChanged = filter.SourceDateTime THEN #TargetState ELSE cas.[Locked] end,
OUTPUT inserted.Id, inserted.Locked, CASE WHEN inserted.Locked = #TargetState AND
inserted.LastChanged = filter.SourceDateTime THEN 1
WHEN inserted.LastChanged <> filter.SourceDateTime THEN -1 -- out of sync
WHEN deleted.Locked = #TargetState THEN -2 -- was not in a good state
ELSE 0 END --generic failure
INTO #OUTPUT
FROM dbo.Target cas WITH(READPAST, UPDLOCK, ROWLOCK) INNER JOIN #table filter ON cas.Id = filter.Id
INSERT INTO #OUTPUT
SELECT filter.id, NULL, when cas.id is not null -3 -- row was/is locked
else -4 end --not found
FROM #table filter left join dbo.target cas with(nolock) on filter.id = cas.id
WHERE NOT EXISTS (SELECT 1 FROM #OUTPUT result WHERE filter.id = result.UpdatedId)
I do not think what you want is possible.
You start with a table to be updated. Let’s say this table contains a set of IDs, say, 1 to 6
You join onto a temp table containing a different set of IDs that may partially overlap (say, 4 to 9)
You issue the update using an inner join. Only rows 4 to 6 are updated
The output clause picks up data only for modified rows, so you only get data for rows 4 to 6
If you flipped this to an outer join (such that all temp table rows are selected), you still only update rows 4 to 6, and the output clause still only kicks out data for rows 4 to 6
So, no, I see no way of achieving this goal in a single SQL statement.

need clarification on where not exists clause

I am trying to insert only those records into #AltDealNames table for which DealName exists in #DistDeal table but not in #AltDealNames table. For this I am trying not exists clause. But it is not working as expected. Query is simply dumping records into #AltDealNames table.
insert into #AltDealNames
select d.DealName, d.ManagerScrubbed, d.BbgDealName, t.TrancheName, t.StreetCusip, t.ISIN, t.BbgTrancheName
from metric..Deal d join metric..Tranche t on d.DealName = t.DealName
where not exists(select 1 from #DistDeal dd join #AltDealNames ad on ad.DealName = dd.DealName)
Please help me to know if I am doing something wrong while building query.
If I understand correctly, you want an exists clause for #DistDeal and a not exists for #AltDealNames:
insert into #AltDealNames
select d.DealName, d.ManagerScrubbed, d.BbgDealName, t.TrancheName,
t.StreetCusip, t.ISIN, t.BbgTrancheName
from metric..Deal d join
metric..Tranche t
on d.DealName = t.DealName
where exists (select 1 from #DistDeal dd where dd.DealName = d.DealName) and
not exists (select 1 from #AltDealNames ad on ad.DealName = dd.DealName);
Note: when using insert, you should always include the list of column names.
Depending on how the optimizer sets up the actual physical query, the "where not exists" clause might run first, before anything is inserted by this query. Ie., it would only filter on values in #AltDealNames that were there from a previous query.
If you're trying to avoid inserting DealName values that are in #DistDeal, then maybe you want:
insert into #AltDealNames
select d.DealName, d.ManagerScrubbed, d.BbgDealName, t.TrancheName,
t.StreetCusip, t.ISIN, t.BbgTrancheName
from metric..Deal d
join metric..Tranche t on d.DealName = t.DealName
where not exists(select 1 from #DistDeal dd
where d.DealName = dd.DealName) -- Changed line

Copy values from one table to another in SQL

I have 2 tables. I need to update all rows of table 1 with the values in specific columns from table 2. They have the same structure.
UPDATE #TempTable
SET [MyColumn] =
(
SELECT [MyColumn]
FROM
[udf_AggregateIDs] (#YearId) AS [af]
INNER JOIN [MyForm] ON
(
[af].[FormID] = [MyForm].[FormID] AND
[af].[FormID] = #MyFormId
)
WHERE [Description] = [MyForm].[Description]
)
I get an error saying Subquery returned more than 1 value. I only added the where clause in because i thought sql is struggling to match the rows, but both tables have the same rows.
It should return multiple values because i'm trying to copy across all rows for MyColumn from the one table to the other.
Ideas?
is Description unique ?
select [Description], count(*) from [MyForm] group by [Description] having count(*)>1
You don't need a sub query..just join the tables..
same type of question has been answered here. Hope it helps.
Have to guess here because your query isn't self-documenting. Does MyColumn come from the function? Does #TempTable have a description column? Who knows, because you didn't prefix them with an alias? Try this. You may have to adjust since you know your schema and we don't.
UPDATE t
SET [MyColumn] = func.MyColumn -- have to guess here
FROM dbo.[udf_AggregateIDs] (#YearId) AS func
INNER JOIN dbo.MyForm AS f
ON func.FormID = f.FormID
INNER JOIN #TempTable AS t
ON t.Description = f.Description -- guessing here also
WHERE f.FormID = #MyFormID;

How do I INSERT INTO where many fields have their own Select Statements?

I created a table and i am in the process of inserting rows from another table into it. However, some of these rows require joins from other tables. To my knowledge, this means using a subquery select statement in the statement. the problem is subqueries only return one result, where i may have many. I am wanting to return a -1 where no records exists. Here is an example i am using but it is not working:
INSERT INTO [BDW_ReportPrototype].[dbo].[CustomerCreditFact]
( [MortgageDimID]
,[LeaseDimID]
,[OREODimID]
,[OfficerTypeDimID] )
SELECT
--[MortgageDimID]
-2
--LeaseDimID
,-2
--OREODimID
,-2
,CASE WHEN OfficerTypeDimID IS NULL THEN -1 ELSE OfficerTypeDimID END
FROM Staging_FDB_LN_CPDM_Daily LCD
LEFT OUTER JOIN ERMA..OfficerTypeDim OTD on OTD.OfficerNum = LCD.OFFICER
FROM dbo.Staging_FDB_LN_CPDM_Daily
Try this sql statement
SELECT CASE WHEN OfficerTypeDimID IS NULL THEN -1 ELSE OfficerTypeDimID END
FROM Staging_FDB_LN_CPDM_Daily LCD
LEFT OUTER JOIN ERMA..OfficerTypeDim OTD on OTD.OfficerNum = LCD.OFFICER
I would rework your query like the following.
First of all, use a LEFT OUTER JOIN in your query instead of the subqueries. This type of join says a row might exist in the "other" table but it might not but I want a row back regardless.
Now that you know you'll have all your rows, you'll want to see if there is a value there or not. Use the shorthand and easier to maintain check via the coalesce function. It basically is a list of values (column names, variables or hard coded values) and the optimizer will pick the first non-null value from the list and use it. Here we supply -1 for your query
INSERT INTO
[BDW_ReportPrototype].[dbo].[CustomerCreditFact]
(
[OfficerTypeDimID]
)
SELECT
-- coalesce returns the first non-null value
COALESCE(OTD.OfficerTypeDimID, -1) AS OfficerTypeDimID
FROM
dbo.Staging_FDB_LN_CPDM_Daily LCD
LEFT OUTER JOIN
ERMA..OfficerTypeDim OTD
ON OTD.OfficerNum = LCD.OFFICER
maybe something along these lines...
INSERT INTO [BDW_ReportPrototype].[dbo].[CustomerCreditFact]
([OfficerTypeDimID])
Select OfficerTypeDimID
from ERMA..OfficerTypeDim OTD
inner JOIN Staging_FDB_LN_CPDM_Daily LCD
on OTD.OfficerNum = LCD.OFFICER
UNION ALL
SELECT -1
FROM dbo.Staging_FDB_LN_CPDM_Daily LCD
WHERE NOT EXISTS
(
Select OfficerTypeDimID from ERMA..OfficerTypeDim
OTD
WHERE
OTD.OfficerNum = LCD.OFFICER
)