存储过程连接上的表参数和列名称上的自动增量ID

时间:2014-01-12 14:41:31

标签: sql-server sql-server-2008

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

1 个答案:

答案 0 :(得分:1)

棘手。我被骗了...

我的假设进入:

  • 来自传入的数据集
  • 提取唯一的摄像机列表(按别名,品牌和型号)
  • 如果它们不在那里,则将它们添加到TestTableCamera

首先,我修改了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子句将三列和新标识值转储到临时表中,并在更小的临时表上执行连接。