CREATE TABLE dbo.TestTableCamera
(
Id int,
AliasTitle nvarchar(500),
Make nvarchar(500),
Model nvarchar(MAX)
)
我有一个作为数据表传递给存储过程的类型。我想首先将某些列插入到一个表中(如果它们不存在)并将主键id附加到别名标题。在此之后,我想插入到另一个表格中,即相机ID插入相机表格的图像表格。我需要保持参照完整性但不确定如何确定摄像机的哪个ID属于哪个图像。我也不确定如何将主键的id附加到别名标题。
CREATE TYPE [dbo].[MediaGalleryFlickrImportParameters] AS TABLE
(
Title nvarchar(500),
Description nvarchar(MAX),
Hits bigint,
CameraAliasTitle nvarchar(255),
CameraMake nvarchar(55),
CameraModel nvarchar(100)
)
我有两张桌子
CREATE TABLE dbo.TestTableImage
(
Id int,
AliasTitle nvarchar(500),
Title nvarchar(500),
Description nvarchar(MAX),
Hits bigint,
CameraId int
)
CREATE TABLE dbo.TestTableCamera
(
Id int,
AliasTitle nvarchar(500),
Make nvarchar(500),
Model nvarchar(MAX)
)
我的程序是
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE dbo.media_gallery_flickr_import
(
@dataImported [dbo].[MediaGalleryFlickrImportParameters] READONLY
)
AS
BEGIN
DECLARE @InsertedCameraId bigint;
SET NOCOUNT ON;
/*Camera Details*/
--IF (NOT NULLIF(@PreviousStartDate, '') IS NULL AND NOT NULLIF(@PreviousStartDate, '') IS NULL)
--BEGIN
INSERT INTO TestTableCamera (AliasTitle, Make, Model)
SELECT DISTINCT CONCAT (CameraAliasTitle,'-',(SELECT ISNULL (MAX(Id)+1,0) FROM TestTableCamera)), CameraMake, CameraModel
FROM @dataImported di
WHERE
NOT EXISTS (SELECT * FROM TestTableCamera c
WHERE
di.CameraAliasTitle = c.AliasTitle
AND di.CameraMake = c.Make
AND di.CameraModel = c.Model)
AND NOT NULLIF(di.CameraAliasTitle, '') IS NULL
AND NOT NULLIF(di.CameraMake, '') IS NULL
AND NOT NULLIF(di.CameraModel, '') IS NULL
-- SET @InsertedCameraId = (SELECT Id FROM camera WHERE make = 'tes');
--END
INSERT INTO dbo.TestTableImage
(Title, Description, Hits)
SELECT
Title, Description, Hits
FROM
@dataImported
END
GO
我以为我可以通过自动增量色彩来做这些事情
INSERT INTO TestTableCamera (AliasTitle, Make, Model)
SELECT DISTINCT CONCAT (CameraAliasTitle,'-',(SELECT ISNULL(MAX(id)+1,0) FROM TestTableCamera)), CameraMake, CameraModel
FROM @dataImported di
WHERE
NOT EXISTS (SELECT * FROM camera c
WHERE
NOT NULLIF(di.CameraAliasTitle, '') IS NULL
AND NULLIF(di.CameraMake, '') IS NULL
AND NULLIF(di.CameraModel, '') IS NULL
AND di.CameraAliasTitle = c.AliasTitle
AND di.CameraMake = c.Make
AND di.CameraModel = c.Model)
我现在用触发器处理别名标题更新,不确定这是否是最好的
ALTER TRIGGER InsertedCameraAlias ON TestTableCamera
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF UPDATE(Id)
BEGIN
UPDATE dbo.TestTableCamera
SET AliasTitle = Concat(a.AliasTitle,'-', a.Id)
FROM dbo.TestTableCamera a
JOIN inserted i ON a.ID = i.ID
--WHERE id EXISTS IN(SELECT id from inserted)
END
END
GO
答案 0 :(得分:1)
棘手。我被骗了...
我的假设进入:
首先,我修改了TestTableCamera,使第一列成为主键并将其设置为标识列:
CREATE TABLE dbo.TestTableCamera
(
Id int identity(1,1) primary key, -- Added identity property
AliasTitle nvarchar(500),
Make nvarchar(500),
Model nvarchar(MAX)
)
接下来,创建一个程序来完成工作。评论内容为什么和为什么:
IF objectproperty(object_id('dbo.media_gallery_flickr_import'), 'isProcedure') = 1
DROP PROCEDURE dbo.media_gallery_flickr_import
GO
CREATE PROCEDURE dbo.media_gallery_flickr_import
@dataImported as dbo.MediaGalleryFlickrImportParameters READONLY
AS
SET NOCOUNT on
DECLARE @NewIds table (Id int not null)
-- Extract list of cameras from the passed-in data
-- Use the EXCEPT clause to filter out any items already in the target table
-- Bonus: using EXCEPT removed dupicates
-- Any rows added are caught by the output clause (we only need Id)
INSERT TestTableCamera (AliasTitle, Make, Model)
output inserted.Id
into @NewIds
select CameraAliasTitle, CameraMake, CameraModel
from @dataImported
except select AliasTitle, Make, Model
from TestTableCamera
-- For all rows inserted (and caught by the output clause),
-- update their AliasTitle with the newly-generated Id.
-- The primary key ensures that this will perform optimally
UPDATE TestTableCamera
set AliasTitle = AliasTitle + ' - ' + cast(ni.Id as varchar(10))
from TestTableCamera ttc
inner join @NewIds ni
on ni.Id = ttc.Id
RETURN 0
GO
接下来,测试一下。创建了一些虚拟数据集
SET NOCOUNT on
TRUNCATE TABLE TestTableCamera
DECLARE
@TestSet_1 dbo.MediaGalleryFlickrImportParameters
-- Four new cameras
INSERT @TestSet_1 values
('Title 1', 'This is the first item', 100, 'Camera Alias A', 'Make AA', 'Model 1')
,('Title 2', 'This is the second item', 200, 'Camera Alias A', 'Make AA', 'Model 1')
,('Title 3', 'This is the third item', 300, 'Camera Alias B', 'Make BB', 'Model 2')
,('Title 4', 'This is the fourth item', 400, 'Camera Alias C', 'Make BB', 'Model 3')
,('Title 5', 'This is the fifth item', 500, 'Camera Alias D', 'Make CC', 'Model 1')
EXECUTE media_gallery_flickr_import @TestSet_1
SELECT * from TestTableCamera order by Id
一次运行这一组,事情看起来很不错......但这是过度自信的迹象。继续测试!
设置一系列测试:
SET NOCOUNT on
TRUNCATE TABLE TestTableCamera
DECLARE
@TestSet_1 dbo.MediaGalleryFlickrImportParameters
,@TestSet_2 dbo.MediaGalleryFlickrImportParameters
-- Four new cameras
INSERT @TestSet_1 values
('Title 1', 'This is the first item', 100, 'Camera Alias A', 'Make AA', 'Model 1')
,('Title 2', 'This is the second item', 200, 'Camera Alias A', 'Make AA', 'Model 1')
,('Title 3', 'This is the third item', 300, 'Camera Alias B', 'Make BB', 'Model 2')
,('Title 4', 'This is the fourth item', 400, 'Camera Alias C', 'Make BB', 'Model 3')
,('Title 5', 'This is the fifth item', 500, 'Camera Alias D', 'Make CC', 'Model 1')
EXECUTE media_gallery_flickr_import @TestSet_1
SELECT 'First pass' [ ], * from TestTableCamera order by Id
-- Do it again, show that nothing new comes in
EXECUTE media_gallery_flickr_import @TestSet_1
SELECT 'Second pass' [ ], * from TestTableCamera order by Id
-- One new camera, one repeat
INSERT @TestSet_2 values
('Title 1', 'This is a duplicate of the first item', 100, 'Camera Alias A', 'Make AA', 'Model 1')
,('Title 6', 'This is the sixth item', 600, 'Camera Alias E', 'Make DD', 'Model 7')
EXECUTE media_gallery_flickr_import @TestSet_2
SELECT 'Third pass' [ ], * from TestTableCamera order by Id
运行这个,然后......惊喜!我们已经修改了列“AliastTitle”,因为它始终是唯一的,因此永远不会匹配同一个摄像机的后续提交。回到绘图板。
我在这看到两个选项。第一个是将逻辑放在EXCEPT
子句中,仅通过“ - ”部分返回字符串。这是一种愚蠢,笨拙,留给学生的练习。
第二个选项是延迟并添加一个计算列,如下所示:
DROP TABLE TestTableCamera
CREATE TABLE dbo.TestTableCamera
(
Id int identity(1,1) primary key, -- Added identity property
AliasTitle nvarchar(500),
AdjustedAlias as AliasTitle + ' - ' + cast(Id as varchar(10)),
Make nvarchar(500),
Model nvarchar(MAX)
)
通过删除output
表格工作来修改程序:
IF objectproperty(object_id('dbo.media_gallery_flickr_import'), 'isProcedure') = 1
DROP PROCEDURE dbo.media_gallery_flickr_import
GO
CREATE PROCEDURE dbo.media_gallery_flickr_import
@dataImported as dbo.MediaGalleryFlickrImportParameters READONLY
AS
SET NOCOUNT on
-- Extract list of cameras from the passed-in data
-- Use the EXCEPT clause to filter out any items already in the target table
-- Bonus: using EXCEPT removed dupicates
INSERT TestTableCamera (AliasTitle, Make, Model)
select CameraAliasTitle, CameraMake, CameraModel
from @dataImported
except select AliasTitle, Make, Model
from TestTableCamera
RETURN 0
GO
再次运行测试,现在您可以获得所需的结果。更过分自信?也许,但它似乎解决了所陈述的问题。计算列也是kludgy,但似乎最好保留AliasTitle的原始形式的副本。适当地重命名列,事情应该成功。
如果没有别的,这一切应该会给你一些关于如何解决问题的想法!
ADDENDA,回复评论:
修改了带有标识属性和主要密钥的TestTableImage,以及确保CameraId有效的外键:
CREATE TABLE dbo.TestTableImage
(
Id int identity(1,1) primary key,
AliasTitle nvarchar(500),
Title nvarchar(500),
Description nvarchar(MAX),
Hits bigint,
CameraId int
constraint FK_TestTableImage__TestTableCamera
foreign key references TestTableCamera (Id)
)
使用带有计算列的TestTableCamera修改存储过程(仅更改是第二个INSERT
语句):
IF objectproperty(object_id('dbo.media_gallery_flickr_import'), 'isProcedure') = 1
DROP PROCEDURE dbo.media_gallery_flickr_import
GO
CREATE PROCEDURE dbo.media_gallery_flickr_import
@dataImported as dbo.MediaGalleryFlickrImportParameters READONLY
AS
SET NOCOUNT on
-- Extract list of cameras from the passed-in data
-- Use the EXCEPT clause to filter out any items already in the target table
-- Bonus: using EXCEPT removed dupicates
INSERT TestTableCamera (AliasTitle, Make, Model)
select CameraAliasTitle, CameraMake, CameraModel
from @dataImported
except select AliasTitle, Make, Model
from TestTableCamera
-- With camera now defined, join in on it by the "natural key"
-- (AliastTitle, Make, Model uniquely identify a camera, it was
-- either already in the table or we just added it, so we can
-- just join on it)
INSERT TestTableImage (AliasTitle, Title, Description, Hits, CameraId)
select ttc.AdjustedAlias, di.Title, di.Description, di.Hits, ttc.Id
from @dataImported di
inner join TestTableCamera ttc
on ttc.AliasTitle = di.CameraAliasTitle
and ttc.Make = di.CameraMake
and ttc.Model = di.CameraModel
RETURN 0
GO
运行测试,你会看到它的工作原理(虽然因为外键你必须用
替换TRUNCATE TABLE
DELETE TestTableImage
DELETE TestTableCamera
如果没有计算列,则必须加入未修改的AliasTitle;截断附加的Id是丑陋的代码和丑陋的连接,使得在calcluated列上有一个非常强大的参数。 (那么为什么要将ID附加到别名?)
当然,正如在大型表上写的那样,这可能会非常慢,因为没有索引可以支持三列连接。这里的修复是创建这样的索引,或使用output
子句将三列和新标识值转储到临时表中,并在更小的临时表上执行连接。