插入一行时,可以将`ParentId`设置为同一查询中前一个插入行的`Id`吗?

时间:2018-02-08 11:05:12

标签: sql-server xml tsql sql-insert

假设我有一个名为@tblTemp的表格,如下所示:

DECLARE @tblTemp TABLE
                 (
                     Id INT NOT NULL IDENTITY,
                     Name VARCHAR(MAX) NOT NULL,
                     ParentId INT NULL
                 )

我的XML结构(分配给@Xml)是:

<Data>
    <MyRow Name="I am the Parent"/>
    <MyRow Name="I am the child" ParentName="I am the Parent"/>
</Data>

问题:是否可以在同一查询中插入ParentId列?

SQL脚本

INSERT INTO @tblTemp ([Name], [ParentId])
    SELECT
        Rw.value('@Name','VARCHAR(MAX)'), -- Name
        (SELECT [Id]  -- Select ID From Parent Name
         FROM @tblTemp AS [TT] 
         WHERE [TT].[Name] = Rw.value('@ParentName', 'VARCHAR(MAX)'))
    FROM 
        @Xml.nodes('Data/MyRow') AS Data(Rw)

SELECT * 
FROM @tblTemp AS [TT]

该脚本会将NULL插入ParentId列,因为我怀疑先前的插入尚未提交,因此该表将为空。

替代方案:如果无法在同一查询中插入ParentId列,那么我的替代方法是执行插入,然后在需要时更新表。

1 个答案:

答案 0 :(得分:1)

试试这样:

public class AndroidLauncher extends AndroidApplication {

    private AdView adView;

    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();

        RelativeLayout layout = new RelativeLayout(this);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
        layout.setLayoutParams(params);

        View gameView=initializeForView(new BuckyRun(), config);

        RelativeLayout.LayoutParams gameViewParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        gameViewParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
        gameViewParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);

        gameView.setLayoutParams(gameViewParams);
        layout.addView(gameView);

        adView = new AdView(this);
        adView.setAdSize(AdSize.BANNER);
        adView.setAdUnitId("secret");

        AdRequest.Builder adRequestBuilder = new AdRequest.Builder();
        adView.loadAd(adRequestBuilder.build());

        RelativeLayout.LayoutParams topParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        topParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,RelativeLayout.TRUE);
        topParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
        layout.addView(adView, topParams);
        adView.setBackgroundColor(android.graphics.Color.TRANSPARENT);

        setContentView(layout);


    }

    @Override
    protected void onResume() {
        super.onResume();
        adView.resume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        adView.pause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        adView.destroy();
    }

结果

DECLARE @tblTemp TABLE
                 (
                     Id INT NOT NULL,
                     Name VARCHAR(MAX) NOT NULL,
                     ParentId INT NULL
                 )
DECLARE @xml XML=
N'<Data>
    <MyRow Name="I am the Parent"/>
    <MyRow Name="I am the child" ParentName="I am the Parent"/>
    <MyRow Name="another child" ParentName="I am the Parent"/>
    <MyRow Name="baby" ParentName="I am the child"/>
</Data>';

WITH DerivedTable AS
(
    SELECT r.value(N'@Name',N'nvarchar(max)') AS [Name]
          ,r.value(N'@ParentName',N'nvarchar(max)') AS [ParentName]
          ,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNmbr
    FROM @xml.nodes(N'/Data/MyRow') AS A(r)
)
,recCTE AS
(
    SELECT 1 AS Lvl
          ,[Name]
          ,[ParentName]
          ,RowNmbr
          ,CAST(NULL AS BIGINT) AS ParentRowNmbr
          ,CAST(N'' AS NVARCHAR(MAX)) AS [ParentPath]
    FROM DerivedTable 
    WHERE ParentName IS NULL

    UNION ALL

    SELECT r.Lvl+1
          ,t.[Name]
          ,t.[ParentName]
          ,t.RowNmbr
          ,r.RowNmbr
          ,r.[ParentPath]+t.[ParentName]+N'|'
    FROM DerivedTable AS t
    INNER JOIN recCTE AS r ON r.[Name]=t.[ParentName]
)
--Use this SELECT to see all columns returned by the recursive CTE
--SELECT * FROM recCTE

INSERT INTO @tblTemp(ID,[Name],ParentId)
SELECT RowNmbr, [Name],ParentRowNmbr
FROM recCTE;

SELECT * FROM @tblTemp;

简短说明:

第一个CTE会将值读取为派生表,并使用Id Name ParentId 1 I am the Parent NULL 2 I am the child 1 3 another child 1 4 baby 2 将每行的运行编号作为ID。
第二个CTE递归地沿着道路行进 结果可以直接插入到您的表格中。

<强>注意

我将您的表从ROW_NUMBER()更改为普通的INT列。您可以先使用ID is IDENTITY获取最高的现有ID,然后将其添加到第一个CTE中的SELECT MAX(ID)。否则可能会发生ROW_NUMBER()给出的ID与ROW_NUMBER()给出的ID不同。