WAITFOR DELAY 不会在每个 WHILE 循环中单独执行

WAITFOR DELAY doesn't act separately within each WHILE loop

我一直在自学使用 WHILE 循环,并决定尝试制作一个有趣的俄罗斯轮盘模拟游戏。也就是说,一个查询将随机 SELECT(或 PRINT)最多 6 个语句(左轮手枪中的每个腔室一个),最后一个语句读取 "you die!" 和任何在此读取之前 "you survive."

我首先创建了一个 table #Nums,其中包含随机顺序的数字 1-6。然后我有一个如下的 WHILE 循环,如果选择了包含 "bullet" (1) 的腔室,则有一个 BREAK(我知道有更简单的方法来选择随机数,但这改编自我正在玩的其他东西之前,我没有兴趣改变它):

SET NOCOUNT ON

CREATE TABLE #Nums ([Num] INT)
DECLARE @Count INT = 1
DECLARE @Limit INT = 6
DECLARE @Number INT

WHILE @Count <= @Limit
BEGIN
SET @Number = ROUND(RAND(CONVERT(varbinary,NEWID()))*@Limit,0,1)+1
IF NOT EXISTS (SELECT [Num] FROM #Nums WHERE [Num] = @Number)
BEGIN
INSERT INTO #Nums VALUES(@Number)
SET @Count += 1
END
END

DECLARE @Chamber INT

WHILE 1=1
BEGIN
  SET @Chamber = (SELECT TOP 1 [Num] FROM #Nums)
    IF @Chamber = 1
    BEGIN
      SELECT 'you die!' [Unlucky...]
      BREAK
    END
  SELECT
   'you survive.' [Phew...]
  DELETE FROM #Nums WHERE [Num] = @Chamber
END

DROP TABLE #Nums

这很好用,但结果都是瞬间出现的,我想在每个结果之间添加一个延迟以增加一点紧张感。

我尝试使用 WAITFOR DELAY 如下:

WHILE 1=1
BEGIN
WAITFOR DELAY '00:00:03'
  SET @Chamber = (SELECT TOP 1 [Num] FROM #Nums)
    IF @Chamber = 1
    BEGIN
      SELECT 'you die!' [Unlucky...]
      BREAK
    END
  SELECT
   'you survive.' [Phew...]
  DELETE FROM #Nums WHERE [Num] = @Chamber
END

我希望 WAITFOR DELAY 最初会导致 3 秒的延迟,然后第一个 SELECT 语句被执行并且文本出现在结果网格中,然后,假设实时室没有被选中,因为还会有3秒的延迟等等,直到选中live chamber。

但是,在我的结果网格中出现任何内容之前,每执行 SELECT 条语句会有 3 秒的延迟,之后所有结果会同时出现。 我尝试使用 PRINT 而不是 SELECT 但遇到了同样的问题。

显然我在这里遗漏了一些东西 - 任何人都可以对此有所了解吗?

这叫做缓冲。服务器不想 return 只有部分完整的响应,因为大多数时候,所有网络开销都需要考虑。许多非常小的包比几个大包贵1.

如果您使用 RAISERROR(不用担心这里我们使用 10 的名称),您可以指定 NOWAIT 来表示 "send this immediately"。 PRINT 或 returning 结果集没有等效项:

SET NOCOUNT ON

CREATE TABLE #Nums ([Num] INT)
DECLARE @Count INT = 1
DECLARE @Limit INT = 6
DECLARE @Number INT

WHILE @Count <= @Limit
BEGIN
SET @Number = ROUND(RAND(CONVERT(varbinary,NEWID()))*@Limit,0,1)+1
IF NOT EXISTS (SELECT [Num] FROM #Nums WHERE [Num] = @Number)
BEGIN
INSERT INTO #Nums VALUES(@Number)
SET @Count += 1
END
END

DECLARE @Chamber INT

WHILE 1=1
BEGIN
WAITFOR DELAY '00:00:03'
  SET @Chamber = (SELECT TOP 1 [Num] FROM #Nums)
    IF @Chamber = 1
    BEGIN
      RAISERROR('you die!, Unlucky',10,1) WITH NOWAIT
      BREAK
    END
   RAISERROR('you survive., Phew...',10,1) WITH NOWAIT
  DELETE FROM #Nums WHERE [Num] = @Chamber
END

DROP TABLE #Nums

正如 Larnu 已经提到的 ,这不是 good 使用 T-SQL.

SQL 是一种面向集合的语言。我们尝试 而不是 编写过程代码(先做这个,再做那个,然后多次 运行 这段代码)。我们尝试在单个查询中尽可能多地给服务器并让 计算出如何处理它。虽然 T-SQL确实 有循环的语言支持,但我们尽可能避免使用它们。


1我在这里使用数据包非常。请注意,无论实际上使用什么网络(或无网络本地内存)选项来承载客户端和服务器之间的连接,它都会应用相同的优化。