从sql表中选择,填写不存在的条目

时间:2013-07-11 17:21:46

标签: sql sql-server

我有两张桌子:

Rooms{ roomNum, maxOccupancy}

Reservations{Name, RoomNum}

我想从具有给定房间号的预订中选择所有名称,但如果返回的行数小于该房间号的maxOccupancy,我还想返回空(或“空”)行为空斑点。

所以我知道我需要从:

开始
select Name from Reservations where Reservations.RoomNum=7 and Reservations.RoomNum = Rooms.roomNum

但还有很多工作要做。

修改

样本数据集将是:

Rooms: roomNum, Max Occupancy:
         7    , 4

Reservations: Name, RoomNum:
              Me,    7 
              You,   7

结果将是:

result: Name:
        Me
        You
        null (or "empty", I just need the row to exist)
        null

5 个答案:

答案 0 :(得分:3)

假设适用于Sql Server,以下查询将非常有用:

CREATE TABLE Reservations(
  Name VARCHAR(100),
  RoomNum INT
  )

CREATE TABLE Rooms(
  RoomNum INT,
  MaxSlots INT
  )

INSERT INTO Rooms VALUES(7,4)
INSERT INTO Reservations VALUES('ME',7)
INSERT INTO Reservations VALUES('YOU',7)

-- Here the query!!
WITH temp ( n ) AS (
    SELECT 1 UNION ALL
    SELECT 1 + n FROM temp WHERE n < 100
)

SELECT t.n AS slot, reserv.Name, a.RoomNum
FROM Rooms a
INNER JOIN temp t ON t.n <= a.MaxSlots
LEFT JOIN (
  SELECT r.Name, ROW_NUMBER() OVER(ORDER BY r.NAME) AS SlotNumber
  FROM Reservations r
  ) reserv ON reserv.SlotNumber = t.n

您可以尝试 here

注意:小心应该始终是,n&lt; 100。

(编辑2013-07-14) 这里的解决方案更通用,可以完成多个房间预订:

WITH temp1 ( n ) AS (
  SELECT 1 UNION ALL
  SELECT 1 + n FROM temp1 WHERE n < 100
), temp2 AS (
  SELECT 
  x.RoomNum,
  x.Name,
  DENSE_RANK() OVER (PARTITION BY x.RoomNum ORDER BY x.RoomNum,x.Name) AS ROWNUM
  FROM Reservations x
)

SELECT a.RoomNum, t1.n AS slot, t2.Name
FROM Rooms a
INNER JOIN temp1 t1 ON t1.n <= a.MaxSlots
LEFT JOIN temp2 t2 ON t2.ROWNUM = t1.n AND a.RoomNum = t2.RoomNum
ORDER BY a.RoomNum,t1.n,t2.Name

您可以试试here

答案 1 :(得分:1)

好的,我用动态sql尝试了这个。我不知道你是否想使用动态sql。但在这里:

-- creating temp tables, you will have your own tables
create table #room (room int, mo int)
create table #reservations (name varchar(100), room int)

declare @diff as int
declare @max as int
declare @i as int

declare @sql nvarchar(max)

insert into #room values (7, 4)

insert into #reservations values ('Me', 7)
insert into #reservations values ('You', 7)

--get the max occupancy of the room
Select @max = mo from #room where room = 7
--get the diff
Select @diff = @max - COUNT(*) from #reservations where room = 7

set @i = 1
set @sql = ''


if @max > @diff 
begin        
    -- we want to generate (Select '' union all) for the difference
while @i <= @diff
  begin
   set @sql = @sql + 'Select ''''' + ' union all '
   set @i = @i + 1
  end
end

--chop off the 'union all' at the end
set @sql = SUBSTRING(@sql, 0, len(@sql) - 8)
set @sql = 'Select name from #reservations union all ' + @sql
--select @sql 

execute sp_executesql @sql

drop table #room
drop table #reservations

在上面的脚本中,生成的sql是Select name from #reservations union all Select '' union all Select ''

答案 2 :(得分:1)

这是一个不像其他版本那样精简的版本,但没有必须硬编码或限制。它将生成最大占用空间的房间表,然后填写有预订的房间名称。

/* create your test data */
CREATE TABLE #reservations (Person varchar(50), RoomNum INT)
INSERT INTO #reservations (Person, RoomNum)
VALUES ('Me', '7'),
('You', '7' ),
('Boo', '10'),
('Beyonce', '12')

CREATE TABLE #Rooms (Ulink INT, RoomNum INT, MaxOccupancy INT)
INSERT INTO #Rooms (ULink, RoomNum, MaxOccupancy)
VALUES ('1', '7', '4'),
('2', '10', '2'),
('3', '12', '7')


/* create the final table to be populated */
CREATE TABLE #ResultTable (ULink INT IDENTITY(1,1), Name varchar(50), RoomNum INT)

/* run two cursors to generate all rows and then populate. This could be nested */

DECLARE @roomNum INT
DECLARE @mark INT
DECLARE D_cursor CURSOR FOR
SELECT DISTINCT RoomNum FROM #Rooms
Open D_Cursor
FETCH NEXT FROM D_cursor INTO @roomNum
WHILE @@FETCH_STATUS = 0
BEGIN
SET @mark = (select maxOccupancy FROM #Rooms WHERE RoomNum = @roomNum)
    DECLARE @loop INT
    SET @loop = 1
    WHILE @loop <= @mark
        BEGIN
            INSERT INTO #ResultTable (RoomNum) SELECT RoomNum FROM #Rooms WHERE         RoomNum = @roomNum
            SET @loop = @loop + 1
        END
    FETCH NEXT FROM D_cursor INTO @roomNum
END
CLOSE D_cursor
DEALLOCATE D_cursor

/* second cursor updates */
DECLARE @person Varchar(50)
DECLARE @roomNumB INT
DECLARE @ULink INT
DECLARE D_cursor CURSOR FOR
SELECT DISTINCT Person, RoomNum  FROM #Reservations
Open D_Cursor
FETCH NEXT FROM D_cursor INTO @person, @RoomNumB
WHILE @@FETCH_STATUS = 0
BEGIN

UPDATE #ResultTable 
SET Name = @person 
WHERE RoomNum = @roomNumB 
AND ULink = (SELECT TOP 1 ULink FROM #ResultTable WHERE RoomNum = @roomNumB AND Name IS     NULL ORDER BY ULink ASC)

FETCH NEXT FROM D_Cursor INTO @person, @roomNumB
END
CLOSE D_cursor
DEALLOCATE D_cursor

SELECT * FROM #ResultTable  --This is here to view it all

答案 3 :(得分:0)

这是使用递归CTE的选项:

/* define sample data */
DECLARE @Rooms TABLE
    (
      Room INT ,
      MaxOccupancy INT
    )
DECLARE @Reservations TABLE
    (
      Room INT ,
      NAME VARCHAR(100)
    ) 

INSERT  INTO @Rooms
VALUES  ( 7, 4 )
INSERT  INTO @Reservations
        ( Room, NAME )
VALUES  ( 7, 'ME' ),
        ( 7, 'YOU' );


/*Uses recursive CTE to build a tally table; hardcoded maximum of 10
  Uses a Row_Number() function to order the slots in a given reservation per room
*/

WITH    N AS ( SELECT   num = 1
               UNION ALL
               SELECT   num + 1
               FROM     N
               WHERE    num < 10 /*hardcoded maximum of 10*/
             )
    SELECT  r2.name
    FROM    @Rooms r
            CROSS JOIN N
            LEFT JOIN ( SELECT  Room ,
                                Name ,
                                rn = ROW_NUMBER() OVER ( PARTITION BY Room ORDER BY name )
                        FROM    @Reservations
                      ) r2 ON r.Room = r2.Room
                              AND n.num = r2.rn
    WHERE   N.num <= r.MaxOccupancy

答案 4 :(得分:0)

您可以尝试这样的事情:

DECLARE @count INT
SET @count = 0
create table #empty (name char(2));
WHILE (select MaxOccupancy - (select count(*) from Reservations where roomNum = 7) from Rooms where roomNum = 7) > @count
BEGIN
   insert into #empty select '  '
   SET @count = (@count + 1)
END
select Name
from Reservations
where roomNum = 7
UNION ALL
select Name
from #empty
drop table #empty;