我有两张桌子:
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
答案 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;