视图、存储过程或表定义函数

Posted

技术标签:

【中文标题】视图、存储过程或表定义函数【英文标题】:View, Stored Procedure, or Table Defined Function 【发布时间】:2011-01-26 20:17:44 【问题描述】:

此查询按原样执行。但是,SQL Management Studio 不会将其保存为视图,因为我定义了一个变量。

声明@HighestTransaction int SET @HighestTransaction = (SELECT MAX(CardID) FROM dbo.Transactions) 选择上传。*,交易。* 从上传左外连接 dbo.Transactions ON dbo.Uploads.Code = dbo.Transactions.CardID WHERE (Uploads.Code > CASE WHEN @HighestTransaction 为 NULL THEN -1 ELSE @HighestTransaction END)

我并没有真正玩过存储过程或用户定义的函数,所以我不确定最好的方法来做这件事。或者,如果有更好的写法,我也愿意接受建议。

【问题讨论】:

并在选择中指定你想要的字段。 Select * 是一种特别糟糕的编码实践,因为您有一个联接,所以您将返回一个字段两次,这是一种资源浪费。 如果其中一个表有几个列,另一个是非常具体的视图,并且所有生成的列都将被调用者使用,那么 SELECT * 是否会出现问题?无论如何,我写 SELECT * 是为了节省空间而不是分散其他东西的注意力。真正的查询确实会扩展所有列,因为当您输入 SELECT * 时,VS 和 SQL Management Studio 都会自动执行此操作。 【参考方案1】: 您可以将 MAX 隔离到 CTE 中 没有 GROUP BY 的 MAX 给出一行,所以你在那里使用 ISNULL

类似...

WITh cHighestCard AS
(
   SELECT ISNULL(MAX(CardID), -1) AS MaxCard FROM dbo.Transactions
)
SELECT     STAUpload.*, Transactions.*
FROM         dbo.STAUpload LEFT OUTER JOIN
                      dbo.Transactions ON dbo.STAUpload.Code = dbo.Transactions.CardID
WHERE     dbo.STAUpload.Code > MaxCard --edit, error spotted by martin

编辑:不需要 CTE:它混合了集合和标量。哎呀。

SELECT     STAUpload.*, Transactions.*
FROM         dbo.STAUpload LEFT OUTER JOIN
                      dbo.Transactions ON dbo.STAUpload.Code = dbo.Transactions.CardID
WHERE     dbo.STAUpload.Code >
            (SELECT ISNULL(MAX(CardID), -1) AS MaxCard
                   FROM dbo.Transactions)

【讨论】:

如果 TRANSACTIONS 表中根本没有记录,CTE 会返回 -1 吗? @OMG 小马:是的 CREATE TABLE OMG (Ponies int); SELECT MAX(Ponies) FROM OMG @OMG Ponies:无耻塞...***.com/questions/2552086/… 如上面的 SQL 写的,我得到了关于无法找到 MaxCard 的错误,即使我将 cHighestCard.MaxCard 添加到第二个 SELECT 的列列表中。【参考方案2】:

由于您提到您尝试将其创建为视图,这意味着您可能希望在另一个查询中使用结果。如果这是真的,我会把它设为table-valued function。

【讨论】:

如果没有至少一个参数,我似乎无法让表值函数工作。我真的一点也不想要。可以这样做,还是我应该只定义一个空白并设置默认值? 它必须是一个多语句 TVF,它是优化器的黑匣子 ***.com/questions/510743/…【参考方案3】:

这是一个存储过程。它很容易使用。只需告诉管理工作室您要创建一个新程序,它甚至会为您构建所有基本框架语法。

http://msdn.microsoft.com/en-us/library/ms345415.aspx

【讨论】:

【参考方案4】:

您可以将其重新编码为带有 COALESCE 的子查询以避免重复输入:

SELECT ....
  FROM ....
 WHERE dbo.STAUpload.code > COALESCE( 
       (Select max(cardId) from dbo.transactions),-1)

然后它就变成了一个视图。

【讨论】:

这仍然会执行两次。 (connect.microsoft.com/SQLServer/feedback/details/336002/…) @Martin, @Ken Downs:那时我会考虑 ISNULL。例如,如果 cardID 是 smallint,那么 .code 可能会因为 COALESCE 数据类型处理而被强制转换为 int(尽管优化器可能将 -1 视为 smallint)【参考方案5】:

您可以在存储过程中执行此操作。只需传入您的变量,它就会按需要工作。

在 msdn 或在线书籍上快速搜索和查看存储过程。

【讨论】:

【参考方案6】:

这可能只是一个简单的视图,无需使用 CTE。子查询中针对 SELECT MAX 的 ISNULL 可能更容易解释将 ISNULL 内联到子查询中。

CREATE VIEW Q_SO
AS
SELECT Uploads.*, Transactions.*
FROM Uploads
LEFT OUTER JOIN dbo.Transactions
    ON dbo.Uploads.Code = dbo.Transactions.CardID
WHERE (Uploads.Code > ISNULL((SELECT MAX(CardID) FROM dbo.Transactions),-1))

作为无参数的表值函数

CREATE FUNCTION Q_FN() RETURNS TABLE AS RETURN
SELECT Uploads.*, Transactions.*
FROM Uploads
LEFT OUTER JOIN dbo.Transactions
    ON dbo.Uploads.Code = dbo.Transactions.CardID
WHERE (Uploads.Code > ISNULL((SELECT MAX(CardID) FROM dbo.Transactions),-1))

【讨论】:

【参考方案7】:

只需将初始化 @HighestTansaction 的子查询交叉连接到您的主查询,如下所示:

SELECT Uploads.*, Transactions.*
FROM   Uploads LEFT OUTER JOIN
       dbo.Transactions ON dbo.Uploads.Code = dbo.Transactions.CardID CROSS JOIN
       (SELECT ISNULL(MAX(CardID),-1) FROM dbo.Transactions) m(HighestTransaction)
WHERE  (Uploads.Code > m.HighestTransaction)

【讨论】:

以上是关于视图、存储过程或表定义函数的主要内容,如果未能解决你的问题,请参考以下文章

mysql为四个表创建储存过程或者储存函数

30.4. MySQL函数,存储过程,触发器,视图

要查看的存储过程

触发器,函数,视图,存储过程

mysql视图,存储过程,函数,事务,触发器,以及动态执行sql

MySQL视图存储过程触发器