添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

SQL Server存储过程--从表中获取表名以用于查询,无需使用动态SQL

2 人不认可

我有一个情况,我的数据库表在表名后面都有一个特定的GUID,每次有更新/升级,GUID都会改变。因此,这给存储过程带来了麻烦,因为我必须在存储过程的开头获得当前的GUID(从它所存储的表),并将其附加到表名上,以便查询它。由于我们大多数人都知道的原因,我真的很想避免使用动态SQL。有什么办法可以在不使用动态sql的情况下解决这个问题吗?

9 个评论
Stu
这听起来是一个 可怕的 实现。你问的是如何通过不使用表的name....,来引用表的名字?
没有动态SQL,你不能动态引用一个对象。如果你不想要动态SQL,请修正你的设计。我们甚至不谈这个事实,因为这个设计你肯定也没有参考的完整性。你有一条很长的路要走,但你必须走。
Stu
我想你也可以实现一个视图,为表提供一个一致的名称,当基表被重命名时改变视图,但 重命名表才是正确的方法。
害怕动态SQL 不是一种生活方式,尤其是当你设计的系统绝对需要它的时候。想象一下,因为有人喝了一次漂白剂,就永远不使用漂白剂。旋转视图或同义词可能会有帮助,但这听起来像是一个非常脆弱的系统的基础。
@AaronBertrand 一个更好的比喻是:让漂白剂远离儿童。儿童因漂白剂而中毒的情况经常发生。
伙计们,你们真的认为这是我想出来的吗?我对这个系统没有任何控制权。我只是不得不和它一起工作,并从一个外部数据库连接到它,所以我的手被绑住了。我正在要求解决我所处的情况,不管我是否喜欢。
@user11889334 而且我们都是为了帮助你解决问题,不要把事情当成个人批评(而且你不能指望我们从问题中知道你对现有的设计没有任何发言权--你说的只是你不想使用动态SQL)。
@Aaron - 我不是针对你。我只是在解释为什么告诉我为什么这是一个糟糕的解决方案并不能真正解决这个问题。我非常感谢大家的意见
公平地说,很多在这里发帖的人不知道他们的解决方案是坏的,但 确实 对它有控制权,所以可以修复它。如果一个老太太把她的车带到机械师那里修理尾灯,而他们有一个爆胎,你应该告诉她爆胎的事还是不告诉?有时,更重要的修复是你想要修复的东西的副作用。
sql-server
user11889334
user11889334
发布于 2022-02-28
2 个回答
Dan Guzman
Dan Guzman
发布于 2022-02-28
0 人赞同

一种方法是在存储过程中使用常量名称创建一个同义词,并在创建新表时重新创建同义词。

CREATE OR ALTER PROC dbo.GetFoo
SELECT Col1 FROM Bar;
CREATE TABLE dbo.[Bar-3BFBBE1D-AB03-4F08-AE20-F58F86E79685](Col1 int)
DROP SYNONYM IF EXISTS dbo.Bar;
CREATE SYNONYM dbo.Bar FOR dbo.[Bar-3BFBBE1D-AB03-4F08-AE20-F58F86E79685];
EXEC dbo.GetFoo;
CREATE TABLE dbo.[Bar-BDB462D8-FF8E-4009-A756-71D7B4CE3D07](Col1 int)
DROP SYNONYM IF EXISTS dbo.Bar;
CREATE SYNONYM dbo.Bar FOR dbo.[Bar-3BFBBE1D-AB03-4F08-AE20-F58F86E79685];
EXEC dbo.GetFoo;
那么,要到什么时候,OP才会问他们如何动态地创建/改变所有这些同义词呢? ;)
为了安全起见,我可能会对存储过程进行 sp_recompile ,尽管这应该作为重新创建同义词的结果自动发生,而且即使我们 "确定 "底层表的结构 "永远不会改变"。我已经看到了太多这样设置的神秘失败。
Aaron Bertrand
Aaron Bertrand
发布于 2022-02-28
0 人赞同

你对动态SQL的担心是错误的。

既然你的表名存储在一个表中,而且希望它是一个 uniqueidentifier 类型,而且这不是来自用户的输入,那么这种方法有什么问题呢?你认为哪里有危险?

DECLARE @tablename sysname, @sql nvarchar(max);
SELECT @tablename = QUOTENAME(GUIDcolumn)
  FROM dbo.BrittleTable; -- WHERE ...
SET @sql = N'SELECT whatever FROM ' + @tablename ...;
EXEC sys.sp_executesql @sql;

如果它不是uniqueidentifier类型(为什么不是呢?),而且你担心有人会把别的东西塞进这一列,那么你可以这样做。

DECLARE @tablename sysname, @sql nvarchar(max);
SELECT @tablename = QUOTENAME(GUIDcolumn)
  FROM dbo.BrittleTable
  WHERE TRY_CONVERT(uniqueidentifier, GUIDcolumn) IS NOT NULL;
IF @tablename IS NOT NULL
BEGIN
SET @sql = N'SELECT whatever FROM ' + @tablename ...;
  EXEC sys.sp_executesql @sql;

动态SQL的存在并不等同于危险的存在。像任何东西一样,它可以被滥用,但也可以被负责任地使用,获得巨大的成功,并且零风险。我在这里对 "我们不想使用动态SQL,因为我们听说过一些故事 "的说法进行了反驳。

  • 动态SQL
  •