Rewrite this INSERT *without* the subquery, please? - sql-server

How would this INSERT statement be rewritten without the subquery, so it no longer results in the error "Subqueries are not allowed in this context. Only scalar expressions are allowed"?
INSERT INTO FUNCTIONAL_AREA (
FUNCTIONAL_AREA_UUID
,FUNCTIONAL_CATEGORY_UUID
,CREATE_DATETIME
,CREATE_USER
,LUPDATE_DATETIME
,LUPDATE_USER
,DESCRIPTION
,ITEM_CODE
,IS_ACTIVE
) VALUES (
NEWID()
,(select functional_category_uuid from functional_category where description = 'ADLs')
,GETDATE()
,'11111111-1111-1111-1111-111111111111'
,GETDATE()
,'11111111-1111-1111-1111-111111111111'
,'Bathing - Ability'
,1081
,1)
Thank you!

INSERT INTO FUNCTIONAL_AREA (
FUNCTIONAL_AREA_UUID
,FUNCTIONAL_CATEGORY_UUID
,CREATE_DATETIME
,CREATE_USER
,LUPDATE_DATETIME
,LUPDATE_USER
,DESCRIPTION
,ITEM_CODE
,IS_ACTIVE
)
select NEWID()
,functional_category_uuid
,GETDATE()
,'11111111-1111-1111-1111-111111111111'
,GETDATE()
,'11111111-1111-1111-1111-111111111111'
,'Bathing - Ability'
,1081
,1
from functional_category
where description = 'ADLs'
EDIT Adding:
If you only want one row inserted and you care about which row is selected from functional_category, then either narrow the where clause so only one row comes back, or use an order by and top 1:
INSERT INTO FUNCTIONAL_AREA (
FUNCTIONAL_AREA_UUID
,FUNCTIONAL_CATEGORY_UUID
,CREATE_DATETIME
,CREATE_USER
,LUPDATE_DATETIME
,LUPDATE_USER
,DESCRIPTION
,ITEM_CODE
,IS_ACTIVE
)
select top 1 NEWID()
,functional_category_uuid
,GETDATE()
,'11111111-1111-1111-1111-111111111111'
,GETDATE()
,'11111111-1111-1111-1111-111111111111'
,'Bathing - Ability'
,1081
,1
from functional_category
where description = 'ADLs'
order by <criteria that causes the correct row to be first>

The reason you are getting this error is because the VALUES clause restricts you to inserting one row. When you have a subquery as one of the columns then this could result in more than one value.
You could either do a 'select' insert like others have shown, or you could write the value to a variable and use the TOP 1 clause if the subquery returns more than one row.

Just a little correction if you want to insert exactly one row in all cases:
INSERT INTO FUNCTIONAL_AREA (
FUNCTIONAL_AREA_UUID,
FUNCTIONAL_CATEGORY_UUID,
CREATE_DATETIME,
CREATE_USER,
LUPDATE_DATETIME,
LUPDATE_USER,
DESCRIPTION,
ITEM_CODE,
IS_ACTIVE)
SELECT TOP (1) NEWID(),
functional_category_uuid,
GETDATE(),
'11111111-1111-1111-1111-111111111111',
GETDATE(),
'11111111-1111-1111-1111-111111111111',
'Bathing - Ability',
1081,
1
FROM functional_category
WHERE description = 'ADLs'
or
DECLARE #category_uuid uniqueidentifier
SELECT #category_uuid = functional_category_uuid
FROM functional_category
WHERE description = 'ADLs'
INSERT INTO FUNCTIONAL_AREA (
FUNCTIONAL_AREA_UUID,
FUNCTIONAL_CATEGORY_UUID,
CREATE_DATETIME,
CREATE_USER,
LUPDATE_DATETIME,
LUPDATE_USER,
DESCRIPTION,
ITEM_CODE,
IS_ACTIVE)
VALUES( NEWID(),
#category_uuid,
GETDATE(),
'11111111-1111-1111-1111-111111111111',
GETDATE(),
'11111111-1111-1111-1111-111111111111',
'Bathing - Ability',
1081,
1)

Related

How to get records which has more than one entries on another table

An example scenario for my question would be:
How to get all persons who has multiple address types?
Now here's my sample data:
CREATE TABLE #tmp_1 (
ID uniqueidentifier PRIMARY KEY
, FirstName nvarchar(max)
, LastName nvarchar(max)
)
CREATE TABLE #tmp_2 (
SeedID uniqueidentifier PRIMARY KEY
, SomeIrrelevantCol nvarchar(max)
)
CREATE TABLE #tmp_3 (
KeyID uniqueidentifier PRIMARY KEY
, ID uniqueidentifier REFERENCES #tmp_1(ID)
, SeedID uniqueidentifier REFERENCES #tmp_2(SeedID)
, SomeIrrelevantCol nvarchar(max)
)
INSERT INTO #tmp_1
VALUES
('08781F73-A06B-4316-B6A5-802ED58E54BE', 'AAAAAAA', 'aaaaaaa'),
('4EC71FCE-997C-46AA-B119-6C5A2545DDC2', 'BBBBBBB', 'bbbbbbb'),
('B0726ABF-738E-48BC-95CB-091C9D731A0E', 'CCCCCCC', 'ccccccc'),
('6C6CE284-A63C-49D2-B2CC-F25C9CBC8FB8', 'DDDDDDD', 'ddddddd')
INSERT INTO #tmp_2
VALUES
('4D10B4EC-C929-4D6B-8C94-11B680CF2221', 'Value1'),
('4C891FE9-60B6-41BE-A64B-11A9A8B58AB2', 'Value2'),
('6F6EFED6-8EA0-4F70-A63F-6A103D0A71BD', 'Value3')
INSERT INTO #tmp_3
VALUES
(NEWID(), '08781F73-A06B-4316-B6A5-802ED58E54BE', '4D10B4EC-C929-4D6B-8C94-11B680CF2221', 'sdfsdgdfbgcv'),
(NEWID(), '08781F73-A06B-4316-B6A5-802ED58E54BE', '4C891FE9-60B6-41BE-A64B-11A9A8B58AB2', 'asdfadsas'),
(NEWID(), '08781F73-A06B-4316-B6A5-802ED58E54BE', '4C891FE9-60B6-41BE-A64B-11A9A8B58AB2', 'xxxxxeeeeee'),
(NEWID(), '4EC71FCE-997C-46AA-B119-6C5A2545DDC2', '4D10B4EC-C929-4D6B-8C94-11B680CF2221', 'sdfsdfsd'),
(NEWID(), 'B0726ABF-738E-48BC-95CB-091C9D731A0E', '4D10B4EC-C929-4D6B-8C94-11B680CF2221', 'zxczxcz'),
(NEWID(), 'B0726ABF-738E-48BC-95CB-091C9D731A0E', '6F6EFED6-8EA0-4F70-A63F-6A103D0A71BD', 'eerwerwe'),
(NEWID(), '6C6CE284-A63C-49D2-B2CC-F25C9CBC8FB8', '4D10B4EC-C929-4D6B-8C94-11B680CF2221', 'vbcvbcvbcv')
Which gives you:
This is my attempt:
SELECT
t1.*
, Cnt -- not really needed. Just added for visual purposes
FROM #tmp_1 t1
LEFT JOIN (
SELECT
xt.ID
, COUNT(1) Cnt
FROM (
SELECT
#tmp_3.ID
, COUNT(1) as Cnt
FROM #tmp_3
GROUP BY ID, SeedID
) xt
GROUP BY ID
) t2
ON t1.ID = t2.ID
WHERE t2.Cnt > 1
Which gives:
ID FirstName LastName Cnt
B0726ABF-738E-48BC-95CB-091C9D731A0E CCCCCCC ccccccc 2
08781F73-A06B-4316-B6A5-802ED58E54BE AAAAAAA aaaaaaa 2
Although this gives me the correct results, I'm afraid that this query is not the right way to do this performance-wise because of the inner queries. Any input is very much appreciated.
NOTE:
A person can have multiple address of the same address types.
"Person-Address" is not the exact use-case. This is just an example.
The Cnt column is not really needed in the result set.
The way you have named your sample tables and data help little in understanding the problem.
I think you want all IDs which have 2 or more SomeIrrelevantCol values in the last table?
This can be done by:
select * from #tmp_1
where ID in
(
select ID
from #tmp_3
group by ID
having count(distinct SomeIrrelevantCol)>=2
)

How to SELECT specific characters using SQL in SQL server database

How can I select only information that start with a #?
I have a table with 5 columns and in one of the columns i.e. the comments column there is information like:
#2345 Changed by Mark
Paul changed ticket number #5923
Someone changed ticket number #5823 and #9333
#3555 is missing from the list, can only see #5789, #9000 and #4568
In the sample of 4 rows above, I want my select statement to return only ticket numbers as shown below:
comments
#2345
#5923
#5823, #9333
#5789, #9000, #4568
Someone said regular expressions can do the work for me but I am fresh graduate and have never seen such before. Can you help me please??
Select the required fields from your database table using SQL, then perform regex operations on the result in another language such as c++, php etc. when outputting your result to the client
First Create Function To extract #numeric values
CREATE FUNCTION dbo.udf_GetNumeric
(
#strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256
)
AS
BEGIN
DECLARE #intAlpha INT
SET #intAlpha = PATINDEX('%[^#0-9]%', #strAlphaNumeric)
BEGIN
WHILE #intAlpha > 0
BEGIN
SET #strAlphaNumeric = STUFF(#strAlphaNumeric, #intAlpha, 1, '' )
SET #intAlpha = PATINDEX('%[^#0-9]%', #strAlphaNumeric )
END
END
RETURN ISNULL(#strAlphaNumeric,0)
END
GO
By Using Below Code we can Extract the numeric values
Declare #TempTable TABLE(ID Int Identity,Value varchar(1000))
INSERT INTO #TempTable
SELECT '#2345 Changed by Mark'
UNION ALL SELECT 'Paul changed ticket number #5923'
UNION ALL SELECT 'Someone changed ticket number #5823 and #9333'
UNION ALL SELECT '#3555 is missing from the list, can only see #5789, #9000 and #4568'
SELECT ID,
RIGHT(LTRIM(REPLACE(Value,'#',' ,#')),LEN(RTRIM(LTRIM(REPLACE(Value,'#',' ,#'))))-1)AS Value FROM
(
SELECT ID,dbo.udf_GetNumeric(Value) AS Value From #TempTable
)Dt
If you need to extract Numeric values Instead of pre-fixed wirh '#' Symbol
SELECT ID,
REPLACE(RIGHT(LTRIM(REPLACE(Value,'#',' ,#')),LEN(RTRIM(LTRIM(REPLACE(Value,'#',' ,#'))))-1),'#',' ')AS Value FROM
(
SELECT ID,dbo.udf_GetNumeric(Value) AS Value From #TempTable
)Dt
OutPut
ID Value
----------
1 #2345
2 #5923
3 #5823 ,#9333
4 #3555 ,#5789 ,#9000 ,#4568
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
Drop table #TempTable
CREATE TABLE [dbo].#TempTable(
[ID] [int] NOT NULL,
[Value] [varchar](1000) NULL
) ON [PRIMARY]
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (1, N'#2345 Changed by Mark #111111,767677,33333,#5656 vbvb')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (2, N'Paul changed ticket number #5923,5555555 464646 #010101,5555544rrr,wwww AND #4 ')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (3, N'Someone changed ticket number #5823 and #9333,7777')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (4, N'#3555 is missing from the list, can only see #5789, #9000 and #4568')
GO
;WITH cte
AS
(
SELECT ID,Split.a.value('.', 'VARCHAR(1000)') AS TablesData
FROM (
SELECT ID,CAST('<S>' + REPLACE(Value, ' ', '</S><S>') + '</S>' AS XML) AS TablesData
FROM #TempTable
) AS A
CROSS APPLY TablesData.nodes('/S') AS Split(a)
)
,Final
AS
(
SELECT ID,TablesData FROM
(
SELECT ID, Split.a.value('.', 'VARCHAR(1000)') AS TablesData,CHARINDEX('#',Split.a.value('.', 'VARCHAR(1000)')) AS Data2
FROM (
SELECT ID,CAST('<S>' + REPLACE(TablesData, ',', '</S><S>') + '</S>' AS XML) AS TablesData
FROM cte
) AS A
CROSS APPLY TablesData.nodes('/S') AS Split(a)
)DT
WHERE dt.Data2 <>0
)
SELECT DISTINCT ID
,STUFF((
SELECT ', ' + CAST(TablesData AS VARCHAR(50))
FROM Final i
WHERE i.ID = o.ID
FOR XML PATH('')
), 1, 1, '') AS ColumnsWith#ValuesOnly
FROM Final o
ORDER BY 1 ASC
OutPut
ID ColumnsWith#ValuesOnly
---------------------------
1 #2345, #111111, #5656
2 #5923, #010101, #4
3 #5823, #9333
4 #3555, #5789, #9000, #4568
The best way is to use this script below:
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
Drop table #TempTable
CREATE TABLE [dbo].#TempTable(
[ID] [int] NOT NULL,
[Value] [varchar](1000) NULL
) ON [PRIMARY]
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (1, N'#2345 Changed by Mark #111111,767677,33333,#5656 vbvb')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (2, N'Paul changed ticket number #5923,5555555 464646 #010101,5555544rrr,wwww AND #4 ')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (3, N'Someone changed ticket number #5823 and #9333,7777')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (4, N'#3555 is missing from the list, can only see #5789, #9000 and #4568')
GO
;WITH cte
AS
(
SELECT ID,Split.a.value('.', 'VARCHAR(1000)') AS TablesData
FROM (
SELECT ID,CAST('<S>' + REPLACE(Value, ' ', '</S><S>') + '</S>' AS XML) AS TablesData
FROM #TempTable
) AS A
CROSS APPLY TablesData.nodes('/S') AS Split(a)
)
,Final
AS
(
SELECT ID,TablesData FROM
(
SELECT ID, Split.a.value('.', 'VARCHAR(1000)') AS TablesData,CHARINDEX('#',Split.a.value('.', 'VARCHAR(1000)')) AS Data2
FROM (
SELECT ID,CAST('<S>' + REPLACE(TablesData, ',', '</S><S>') + '</S>' AS XML) AS TablesData
FROM cte
) AS A
CROSS APPLY TablesData.nodes('/S') AS Split(a)
)DT
WHERE dt.Data2 <>0
)
SELECT DISTINCT ID
,STUFF((
SELECT ', ' + CAST(TablesData AS VARCHAR(50))
FROM Final i
WHERE i.ID = o.ID
FOR XML PATH('')
), 1, 1, '') AS ColumnsWith#ValuesOnly
FROM Final o
ORDER BY 1 ASC

How can i handle Insert from select statement using trigger in sqlserver

I have the following TSQL statements to insert data from one database Table to another database tables, how can i mange this using Trigger?
the Source table is [DISCS] and the destination tables are,
[WIBOMH] is a Master table, [WIBOMH] is a header table, [WIBOMD] is detail table so
the orders have to be first insert into [WIITEM] then create a header [WIBOMH]
I want to fire this AFTER INSERT. when i added a new DISC into DISC Table i would like to fire the following insert statement
-- Insert into [WIITEM] Table---
INSERT INTO [WIITEM]
([itemId], [descr],[xdesc],[sales] ,[uOfM] ,[poUOfM] ,[uConvFact],[ref],[type],[status],[unitWgt] )
SELECT [itemId], [PURCHASE_DESCRIPTION], [SALES_DESCRIPTION], [sales] ,[uOfM] ,[poUOfM] ,[uConvFact],'TESTING', '2','0',[unitWgt]
FROM [DISCS]
WHERE [itemId] NOT IN (SELECT [itemId] FROM [WIITEM])
AND [makebuy]='Make';
-- Insert into [WIBOMH] Table---
DECLARE #d DATETIME = GETDATE();
INSERT INTO [WIBOMH]
([bomItem], [bomRev], [rollup], [mult], [autoBuild], [assyLead],[revCmnt],[author],[descr],[qPerLead],[lstMainDt],[revDate],[effStartDate],[ovride] )
SELECT DISTINCT [bomitem], 'B', '1', '1', '1', '3','TESTING','USER NAME','TESTING','0', FORMAT(#d, 'yyyy-MM-dd HH\:mm\:ss\.fff', 'en-US') AS 'Format#1',FORMAT(#d, 'yyyyMMdd' , 'en-US') AS 'Format#2',FORMAT(#d, 'yyyyMMdd' , 'en-US') AS 'Format#2','0'
FROM [DISCS]
WHERE [bomitem] IN (SELECT [ItemId] FROM [WIITEM] where type='2')
AND [bomitem] NOT IN (SELECT [bomItem] FROM [WIBOMH]);
-- Insert into [WIBOMD] Table---
INSERT INTO [WIBOMD]
([bomItem], [bomRev], [bomEntry], [partId], [qty],[cmnt],[srcLoc],[dType],[lead],[lineNbr])
SELECT [ItemID], 'B', [bomEntry], [partid], [qty],'TESTING','WSD-DS','0','0', [lineNbr]
FROM [DISCS]
WHERE [ItemID] IN (SELECT [ItemId] FROM [WIITEM] where type='2')
AND [ItemID] NOT IN (SELECT [bomItem] FROM [WIBOMD]);
i tried
INSERT INTO [MITESTCO].[WIITEM]
([itemId], [descr],[xdesc],[sales] ,[uOfM] ,[poUOfM] ,[uConvFact],[ref],[type],[status])
SELECT
[CALC STOCK PN], [PURCHASE DESCRIPTION], [SALES DESCRIPTION], [CALC STOCK PN] ,'EA' ,'EA' ,'1','SYNC FROM PDM', '2','0'--,[APPROX. WGT.]
FROM inserted
WHERE [MAKE / BUY]='Make' [CALC STOCK PN] NOT IN (SELECT [itemId] FROM [MIITEM] WHERE itemId NOT LIKE '*-CI');
but i get
invalid object [MITESTCO].[WIITEM]
here i got the first trigger working
create TRIGGER [dbo].[PNSETUP]
ON [dbo].[DISCS]
AFTER insert,UPDATE
AS
BEGIN
IF TRIGGER_NESTLEVEL() > 1
RETURN
SET ANSI_WARNINGS OFF;
INSERT INTO MITESTCO.dbo.WIITEM
([itemId], [descr],[xdesc],[sales] ,[uOfM] ,[poUOfM] ,[uConvFact],[ref],[type],[status])--,[unitWgt]
SELECT [CALC STOCK PN], [PURCHASE DESCRIPTION], [SALES DESCRIPTION], [CALC STOCK PN] ,'EA' ,'EA' ,'1','SYNC FROM PDM', '2','0'--,[APPROX. WGT.]
FROM [DISCS]
WHERE [CALC STOCK PN] NOT IN (SELECT [itemId] FROM MITESTCO.dbo.[WIITEM] WHERE itemId NOT LIKE '*-CI')
AND [MAKE / BUY]='Make';
SET ANSI_WARNINGS ON;
how can i add the next two insert select statement to same trigger
You can use after insert trigger to update the count after each insertion.
Do you need a trigger ? Do you need to copy the new rows from the table in real time ?
Triggers will KILL the insert performance of your table.
Consider adding a column DateLastCopied to the source table, and then once a minute
declare #now as datetime= getdate()
update sourcetable set DateLastCopied=#now where DateLastCopied is null
insert into targetTable(..)
select ...
FROM sourcetable where DateLastCopied=#now

How to get rid of special characters after generating sql statements using for xml

I have generated insert statements for audit trail using for xml and it generates the correct insert statements. See below is what gets generated.
This is what Print #SQL outputs:
INSERT INTO [AuditLog]
(
[TableName]
,[ColumnName]
,[Value]
,[Action]
,[TimeStamp]
)
SELECT
'Book'
,'BookID'
,CONVERT(VARCHAR(MAX), BookID)
,CONVERT(VARCHAR(MAX), 1)
,getdate()
FROM INSERTED;
INSERT INTO [AuditLog]
(
[TableName]
,[ColumnName]
,[Value]
,[Action]
,[TimeStamp]
)
SELECT
'Book'
,'c_Name'
,CONVERT(VARCHAR(MAX), c_Name)
,CONVERT(VARCHAR(MAX), 1)
,getdate()
FROM INSERTED;
INSERT INTO [AuditLog]
(
[TableName]
,[ColumnName]
,[Value]
,[Action]
,[TimeStamp]
)
SELECT
'Book'
,'c_Author'
,CONVERT(VARCHAR(MAX), c_Author)
,CONVERT(VARCHAR(MAX), 1)
,getdate()
FROM INSERTED;
INSERT INTO [AuditLog]
(
[TableName]
,[ColumnName]
,[Value]
,[Action]
,[TimeStamp]
)
SELECT
'Book'
,'c_Price'
,CONVERT(VARCHAR(MAX), c_Price)
,CONVERT(VARCHAR(MAX), 1)
,getdate()
FROM INSERTED;
However when I try to execute using EXECUTE(#SQL) I get an error message:
Incorrect syntax near '&'.
Unbelievably, I found really simple solution. I used COALESCE function to generate dynamic insert statements and I don't see any special characters as it would otherwise using for xml

SQL Server Another simple question

I have 2 temp Tables [Description] and [Institution], I want to have these two in one table.
They are both tables that look like this:
Table1; #T1
|Description|
blabla
blahblah
blagblag
Table2; #T2
|Institution|
Inst1
Inst2
Inst3
I want to get it like this:
Table3; #T3
|Description| |Institution|
blabla Inst1
blahblah Inst2
blagblag Inst3
They are already in sort order.
I just need to get them next to each other..
Last time I asked was something almost the same.
I used this query
Create Table #T3
(
[From] Datetime
,[To] Datetime
)
INSERT INTO #T3
SELECT #T1.[From]
, MIN(#T2.[To])
FROM #T1
JOIN #T2 ON #T1.[From] < #T2.[To]
GROUP BY #T1.[From]
Select * from #T3
It did work for the date values, but it won't work here ? :s
Thank you.
One thing that concerns me is that you say that the values "are already in sort order". There really is no default sort order -- if you don't specify a sort order, you are at the mercy of SQL Server to determine the order in which the data is returned. The solution below assumes that there is some way to sort the data such that the records "match up" (using the ORDER BY clauses).
Hope this helps,
John
-- Table 1 test data
Create Table #T1
(
[Description] nvarchar(30)
)
INSERT INTO #T1 ([Description]) VALUES ('desc1')
INSERT INTO #T1 ([Description]) VALUES ('desc2')
INSERT INTO #T1 ([Description]) VALUES ('desc3')
-- Table 2 test data
Create Table #T2
(
[Institution] nvarchar(30)
)
INSERT INTO #T2 (Institution) VALUES ('Inst1')
INSERT INTO #T2 (Institution) VALUES ('Inst2')
INSERT INTO #T2 (Institution) VALUES ('Inst3')
-- Create table 3
Create Table #T3
(
[Description] nvarchar(30),
[Institution] nvarchar(30)
);
-- Use CTE2 to add row numbers to the data; use the row numbers to join the tables
-- you must specify the sort order for the data in the tables
WITH CTE1 (Description, RowNum) AS
(
SELECT [Description], ROW_NUMBER() OVER(ORDER BY [Description]) as RowNum
FROM #T1
),
CTE2 (Institution, RowNum) AS
(
SELECT Institution, ROW_NUMBER() OVER(ORDER BY Institution) as RowNum
FROM #T2
)
INSERT INTO #T3
SELECT CTE1.Description, CTE2.Institution
FROM CTE1
LEFT JOIN CTE2 ON CTE1.RowNum = CTE2.RowNum
Select * from #T3

Resources