SQL Server 2008使用while循环填充缺失值

时间:2018-06-11 16:25:15

标签: sql-server-2008

这是我的表格:

table as is

对于Patient Arrive的每个实例,我需要一个其他状态的实例。正如您在此特定情景中所看到的,我有3个患者到达输入;因此,我的状态应如下表2所示:

table should be

这是我到目前为止所做的。

DECLARE @Patient_Leave TABLE 
                 (
                     id     INT,
                     status     VARCHAR (200)
      ,times     VARCHAR (200)

     )
      DECLARE  @arrive INT = 0
        DECLARE  @Leave INT 

          set @Patient_Leave = (select ((select COUNT(status) FROM Parameters VF WITH (NOLOCK) where status ='Patient Arrive) -
           (select COUNT(status) FROM Parameters VF WITH (NOLOCK) where status='Patient leave')))

              WHILE ( @arrive )  < @Leave

                BEGIN
                  INSERT INTO @Patient_Leave

                    select distinct id, status, (select 'No data entered')as Time FROM Parameters VF WITH (NOLOCK) where status='Patient Leave

                         SET  @arrive =  @arrive + 1

                 END

                   SELECT * FROM @Patient_Leave

                          GO

2 个答案:

答案 0 :(得分:0)

Bethony,

我根据您提供的数据构建了以下内容并测试成功。

SQL代码:

USE SO_Tests
GO

--CREATE TABLE Patient_Table
--  (
--      id INT
--      ,status VARCHAR (200)
--      ,times VARCHAR(200)
--     )

TRUNCATE TABLE Patient_Table

INSERT INTO
    Patient_Table
        (ID, status, times)
VALUES
    (123666,'Patient Arrive', '20180606 10:52')
    ,(123666,'Patient Arrive', '20180606 11:21')
    ,(123666,'Patient Arrive', '20180606 11:45')
    ,(123666,'Patient Prepped', '20180606 10:52')
    ,(123666,'Patient Prepped', '20180606 11:45')
    ,(123666,'Patient Leave', '20180606 10:52')
    ,(123666,'Patient Return', '20180606 10:55')
    ,(123666,'Patient Return', '20180606 12:30')
    ,(123666,'Patient Ready', '20180606 12:45')
    ,(123666,'Patient Discharged', '20180606 12:45')

SELECT * FROM Patient_Table

DECLARE @Count_Arrive INT = (SELECT COUNT(*) FROM Patient_Table WHERE status = 'Patient Arrive')
DECLARE @Count_Leave INT = (SELECT COUNT(*) FROM Patient_Table WHERE status = 'Patient Leave')
DECLARE @Count_Prepped INT = (SELECT COUNT(*) FROM Patient_Table WHERE status = 'Patient Prepped')
DECLARE @Count_Return INT = (SELECT COUNT(*) FROM Patient_Table WHERE status = 'Patient Return')
DECLARE @Count_Discharged INT = (SELECT COUNT(*) FROM Patient_Table WHERE status = 'Patient Discharged')
DECLARE @Count_Ready INT = (SELECT COUNT(*) FROM Patient_Table WHERE status = 'Patient Ready')

WHILE(@Count_Arrive <> @Count_Leave OR @Count_Arrive <> @Count_Prepped OR @Count_Arrive <> @Count_Return OR @Count_Arrive <> @Count_Discharged OR @Count_Arrive <> @Count_Ready)
BEGIN

    IF (@Count_Arrive <> @Count_Leave)
    BEGIN
    INSERT INTO 
        Patient_Table
    SELECT
        123456,
        'Patient Leave',
        'No Data Provided'

    SET @Count_Leave = @Count_Leave + 1
    END

    IF (@Count_Arrive <> @Count_Prepped)
    BEGIN
    INSERT INTO 
        Patient_Table
    SELECT
        123456,
        'Patient Prepped',
        'No Data Provided'

    SET @Count_Prepped = @Count_Prepped + 1
    END

    IF (@Count_Arrive <> @Count_Return)
    BEGIN
    INSERT INTO 
        Patient_Table
    SELECT
        123456,
        'Patient Return',
        'No Data Provided'

    SET @Count_Return = @Count_Return + 1
    END

    IF (@Count_Arrive <> @Count_Discharged)
    BEGIN
    INSERT INTO 
        Patient_Table
    SELECT
        123456,
        'Patient Discharged',
        'No Data Provided'

    SET @Count_Discharged = @Count_Discharged + 1
    END

    IF (@Count_Arrive <> @Count_Ready)
    BEGIN
    INSERT INTO 
        Patient_Table
    SELECT
        123456,
        'Patient Ready',
        'No Data Provided'

    SET @Count_Ready = @Count_Ready + 1
    END


END

SELECT * FROM Patient_Table ORDER BY STATUS

结果:Query Results

这涵盖了所需的其他状态,并将虚拟行应用于到达行的计数

<强>更新 在光标中添加以进行患者ID并添加一些额外的处理以防止添加从未记录过的行并避免无限循环,如果另一个状态的行数超过Patient_Arrive每个id

USE SO_Tests
GO

DECLARE @Patient_Table TABLE
  (
      id INT
      ,status VARCHAR (200)
      ,times VARCHAR(200)
     )

--TRUNCATE TABLE Patient_Table

--INSERT INTO
--    Patient_Table
--        (ID, status, times)
--VALUES
--    (123666,'Patient Arrive', '20180606 10:52')
--    ,(123666,'Patient Arrive', '20180606 11:21')
--    ,(123666,'Patient Arrive', '20180606 11:45')
--    ,(123666,'Patient Prepped', '20180606 10:52')
--    ,(123666,'Patient Prepped', '20180606 11:45')
--    ,(123666,'Patient Leave', '20180606 10:52')
--    ,(123666,'Patient Return', '20180606 10:55')
--    ,(123666,'Patient Return', '20180606 12:30')
--    ,(123666,'Patient Ready', '20180606 12:45')
--    ,(123666,'Patient Discharged', '20180606 12:45')



INSERT INTO @Patient_Table SELECT * FROM Patient_Table

DECLARE @id INT

DECLARE Patient_Cursor CURSOR FOR
    SELECT
        id
    FROM
        @Patient_Table

OPEN Patient_Cursor
FETCH NEXT FROM Patient_Cursor INTO @id
WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @Count_Arrive INT = (SELECT COUNT(*) FROM @Patient_Table WHERE status = 'Patient Arrive' AND id = @id)
    DECLARE @Count_Leave INT = (SELECT COUNT(*) FROM @Patient_Table WHERE status = 'Patient Leave' AND id = @id)
    DECLARE @Count_Prepped INT = (SELECT COUNT(*) FROM @Patient_Table WHERE status = 'Patient Prepped' AND id = @id)
    DECLARE @Count_Return INT = (SELECT COUNT(*) FROM @Patient_Table WHERE status = 'Patient Return' AND id = @id)
    DECLARE @Count_Discharged INT = (SELECT COUNT(*) FROM @Patient_Table WHERE status = 'Patient Discharged' AND id = @id)
    DECLARE @Count_Ready INT = (SELECT COUNT(*) FROM @Patient_Table WHERE status = 'Patient Ready' AND id = @id)

    WHILE((@Count_Arrive > @Count_Leave and @Count_Leave > 0) OR (@Count_Arrive > @Count_Prepped and @Count_Prepped > 0) OR (@Count_Arrive > @Count_Return and @Count_Return = 0) OR (@Count_Arrive > @Count_Discharged and @Count_Discharged > 0) OR (@Count_Arrive > @Count_Ready and @Count_Ready > 0))
    BEGIN
    print 'recursing'
    print @count_arrive
    print @count_leave
    print @count_prepped
    print @count_return
    print @count_discharged
    print @count_ready

        IF (@Count_Arrive > @Count_Leave and @Count_Leave > 0)
        BEGIN
        INSERT INTO 
            @Patient_Table
        SELECT
            @id,
            'Patient Leave',
            'No Data Provided'

        SET @Count_Leave = @Count_Leave + 1
        END

        IF (@Count_Arrive > @Count_Prepped and @Count_Prepped > 0)
        BEGIN
        INSERT INTO 
            @Patient_Table
        SELECT
            @id,
            'Patient Prepped',
            'No Data Provided'

        SET @Count_Prepped = @Count_Prepped + 1
        END

        IF (@Count_Arrive > @Count_Return and @Count_Return > 0)
        BEGIN
        INSERT INTO 
            @Patient_Table
        SELECT
            @id,
            'Patient Return',
            'No Data Provided'

        SET @Count_Return = @Count_Return + 1
        END

        IF (@Count_Arrive > @Count_Discharged and @Count_Discharged > 0)
        BEGIN
        INSERT INTO 
            @Patient_Table
        SELECT
            @id,
            'Patient Discharged',
            'No Data Provided'

        SET @Count_Discharged = @Count_Discharged + 1
        END

        IF (@Count_Arrive > @Count_Ready and @Count_Ready > 0)
        BEGIN
        INSERT INTO 
            @Patient_Table
        SELECT
            @id,
            'Patient Ready',
            'No Data Provided'

        SET @Count_Ready = @Count_Ready + 1
        END

    END

    FETCH NEXT FROM Patient_Cursor INTO @id

END
SELECT * FROM Patient_Table
SELECT * FROM @Patient_Table

答案 1 :(得分:0)

我不相信你需要一个光标(尽管使用它可能更有效)。我认为这可以满足您的需求。

WITH Pnumbered AS (
  SELECT
    P.ID, P.status, P.times, ROW_NUMBER() OVER (
      PARTITION BY P.ID, P.status
      ORDER BY P.times
    ) AS rn
  FROM Patient_Table AS P
), PA AS (
   SELECT
    P.ID, P.status, P.times
  FROM Patient_Table AS P
  WHERE P.status = 'Patient Arrive'
), Enough AS (
  SELECT PA.ID, S.status, S.statusseq, ROW_NUMBER() OVER (
      PARTITION BY PA.ID, S.status
      ORDER BY PA.times
    ) AS rn FROM PA
  CROSS JOIN (
    SELECT 'Patient Arrive',1 UNION ALL
    SELECT 'Patient Prepped',2 UNION ALL
    SELECT 'Patient Leave',3 UNION ALL
    SELECT 'Patient Return',4 UNION ALL
    SELECT 'Patient Ready',5 UNION ALL
    SELECT 'Patient Discharged',6
  ) AS S(status,statusseq)
)

SELECT
  Enough.ID, COALESCE(Pnumbered.status, Enough.status) as status, COALESCE(Pnumbered.times,'No Data Provided') AS times
FROM Pnumbered
RIGHT OUTER JOIN Enough
ON Pnumbered.ID = Enough.ID
AND Pnumbered.status = Enough.status
AND Pnumbered.rn = Enough.rn
ORDER BY ID, statusseq

这个想法如下:创建一个表格,每个患者ID和每个status复制的次数与ID的“到达”行数相同,并对副本进行编号。同时按时间顺序对Patient_Data表中具有相同(ID, status)的行进行编号。最后,外连接这两个表,以便获得每个(ID,status)的正确数量的副本,并用“未提供数据”替换外连接中不匹配行的NULL。 (不匹配的行将是给定IDstatus的行超过(ID,status)表中Patient_Data的实际行数。

如果您为Statuses创建了S(status,statusseq)表,则查询看起来会更简单。

这是输出:

ID          status             times
----------- ------------------ -------------------
123666      Patient Arrive     20180606 10:52
123666      Patient Arrive     20180606 11:21
123666      Patient Arrive     20180606 11:45
123666      Patient Prepped    20180606 10:52
123666      Patient Prepped    20180606 11:45
123666      Patient Prepped    No Data Provided
123666      Patient Leave      20180606 10:52
123666      Patient Leave      No Data Provided
123666      Patient Leave      No Data Provided
123666      Patient Return     No Data Provided
123666      Patient Return     20180606 10:55
123666      Patient Return     20180606 12:30
123666      Patient Ready      20180606 12:45
123666      Patient Ready      No Data Provided
123666      Patient Ready      No Data Provided
123666      Patient Discharged No Data Provided
123666      Patient Discharged No Data Provided
123666      Patient Discharged 20180606 12:45
123667      Patient Arrive     20180607 10:52
123667      Patient Prepped    No Data Provided
123667      Patient Leave      No Data Provided
123667      Patient Return     No Data Provided
123667      Patient Ready      No Data Provided
123667      Patient Discharged No Data Provided