SQL 存储过程中的动态排序

2023-11-21

这是我过去花了几个小时研究的一个问题。在我看来,这是现代应该解决的问题RDBMS解决方案,但到目前为止,我还没有找到任何能够真正满足我认为在任何具有数据库后端的 Web 或 Windows 应用程序中非常常见的需求的东西。

我说的是动态排序。在我的幻想世界中,它应该像这样简单:

ORDER BY @sortCol1, @sortCol2

这是新手 SQL 给出的规范示例存储过程互联网上各个论坛的开发者。 “为什么这不可能?”他们问。总是有人最终会向他们讲授存储过程的编译性质、一般执行计划的性质,以及为什么不能将参数直接放入存储过程的各种其他原因。ORDER BY clause.


我知道你们中的一些人已经在想:“那就让客户来分类吧。”当然,这会减轻数据库的工作负担。但就我们而言,我们的数据库服务器在 99% 的时间里都没有出汗,它们甚至还不是多核的,也不是每 6 个月发生一次的系统架构的任何其他无数改进。仅出于这个原因,让我们的数据库处理排序就不成问题了。此外,数据库是very善于排序。他们针对它进行了优化,并且花了很多年的时间来做到这一点,执行此操作的语言非常灵活、直观且简单,最重要的是,任何初学者 SQL 编写者都知道如何执行此操作,更重要的是,他们知道如何编辑它,进行更改、进行维护等。当您的数据库远未被征税并且您只是想简化(并缩短!)开发时间时,这似乎是一个显而易见的选择。

然后是网络问题。我尝试过使用 JavaScript 对 HTML 表进行客户端排序,但它们不可避免地不够灵活,无法满足我的需求,而且,因为我的数据库并没有负担过重,而且确实可以进行排序really很容易,我很难证明重写或滚动我自己的 JavaScript 排序器所需的时间是合理的。服务器端排序通常也是如此,尽管它可能已经比 JavaScript 更受青睐。我不是一个特别喜欢数据集开销的人,所以起诉我吧。

但这又让人回想起这是不可能的——或者更确切地说,不容易。我已经用以前的系统完成了一种令人难以置信的动态排序方式。它不漂亮、也不直观、简单或灵活,初学者 SQL 编写者会在几秒钟内迷失方向。这看起来已经不再是一个“解决方案”,而是一个“复杂化”。


以下示例并不意味着公开任何类型的最佳实践或良好的编码风格或任何内容,也不表明我作为 T-SQL 程序员的能力。它们就是它们本身,我完全承认它们令人困惑,形式糟糕,而且只是简单的黑客攻击。

我们将一个整数值作为参数传递给存储过程(我们将该参数称为“排序”),并从中确定一堆其他变量。例如...假设排序为 1(或默认值):

DECLARE @sortCol1 AS varchar(20)
DECLARE @sortCol2 AS varchar(20)
DECLARE @dir1 AS varchar(20)
DECLARE @dir2 AS varchar(20)
DECLARE @col1 AS varchar(20)
DECLARE @col2 AS varchar(20)

SET @col1 = 'storagedatetime';
SET @col2 = 'vehicleid';

IF @sort = 1                -- Default sort.
BEGIN
    SET @sortCol1 = @col1;
    SET @dir1 = 'asc';
    SET @sortCol2 = @col2;
    SET @dir2 = 'asc';
END
ELSE IF @sort = 2           -- Reversed order default sort.
BEGIN
    SET @sortCol1 = @col1;
    SET @dir1 = 'desc';
    SET @sortCol2 = @col2;
    SET @dir2 = 'desc';
END

您已经可以看到,如果我声明更多 @colX 变量来定义其他列,我真的可以根据“sort”的值对要排序的列发挥创意......使用它,它通常最终看起来像下面这样极其混乱的子句:

ORDER BY
    CASE @dir1
        WHEN 'desc' THEN
            CASE @sortCol1
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END DESC,
    CASE @dir1
        WHEN 'asc' THEN
            CASE @sortCol1
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END,
    CASE @dir2
        WHEN 'desc' THEN
            CASE @sortCol2
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END DESC,
    CASE @dir2
        WHEN 'asc' THEN
            CASE @sortCol2
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END

显然这是一个非常精简的例子。真正的东西,因为我们通常有四到五列支持排序,除此之外,每列还可能有第二列甚至第三列进行排序(例如日期降序,然后按名称升序排序),并且每个列都支持双列定向排序,有效地使案例数量增加一倍。是的...它很快就会长毛。

这个想法是,人们可以“轻松地”更改排序情况,以便在存储日期时间之前对vehicleid进行排序......但是伪灵活性,至少在这个简单的示例中,真的到此为止。本质上,每个测试失败的情况(因为我们的排序方法这次不适用于它)都会呈现一个 NULL 值。因此,您最终会得到一个功能如下的子句:

ORDER BY NULL DESC, NULL, [storagedatetime] DESC, blah blah

你明白了。它之所以有效,是因为 SQL Server 有效地忽略 order by 子句中的空值。这是非常难以维护的,任何具有 SQL 基本工作知识的人都可能会看到。如果我失去了你们中的任何一个,请不要难过。我们花了很长时间才让它工作,但在尝试编辑它或创建类似的新文件时我们仍然感到困惑。值得庆幸的是它不需要经常改变,否则它很快就会变得“不值得这么麻烦”。

Yet it did work.


那么我的问题是:有没有更好的办法?

我对存储过程以外的解决方案很满意,因为我意识到这可能不是正确的选择。最好,我想知道是否有人可以在存储过程中做得更好,但如果不能,你们如何处理让用户使用 ASP.NET 动态排序数据表(也是双向的)?

感谢您阅读(或至少浏览)这么长的问题!

PS:很高兴我没有展示支持动态排序、列的动态过滤/文本搜索、通过 ROWNUMBER() OVER 分页的存储过程示例,AND尝试...捕获错误时的事务回滚...“庞然大物”甚至还没有开始描述它们。


Update:

  • 我想避免动态 SQL。将字符串解析在一起并对其运行 EXEC 从一开始就违背了存储过程的许多目的。有时我想知道这样做的缺点是否不值得,至少在这些特殊的动态排序情况下。尽管如此,每当我执行这样的动态 SQL 字符串时,我总是感觉很肮脏 — 就像我仍然生活在经典 ASP 世界中一样。
  • 我们首先想要存储过程的很多原因是security。我不会就安全问题打电话,只是提出解决方案。使用 SQL Server 2005,我们可以在架构级别对单个存储过程设置权限(如果需要,可以针对每个用户),然后直接拒绝对表的任何查询。批评这种方法的利弊可能是另一个问题,但这又不是我的决定。我只是首席代码猴。 :)

是的,这很痛苦,而且你做的方式看起来和我做的很相似:

order by
case when @SortExpr = 'CustomerName' and @SortDir = 'ASC' 
    then CustomerName end asc, 
case when @SortExpr = 'CustomerName' and @SortDir = 'DESC' 
    then CustomerName end desc,
...

对我来说,这仍然比从代码构建动态 SQL 好得多,后者对 DBA 来说是可扩展性和维护的噩梦。

我在代码中所做的就是重构分页和排序,因此我至少没有大量重复填充值@SortExpr and @SortDir.

就 SQL 而言,在不同的存储过程之间保持相同的设计和格式,这样当您进行更改时,它至少是整洁且可识别的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQL 存储过程中的动态排序 的相关文章

  • xQuery LIKE 运算符?

    有没有办法以与 SQL 相同的方式使用 XQuery 执行 LIKE 操作 我不想构造一些 startswith endswith 和 contains 表达式 我想要实现的目标的示例 for x in user where x first
  • C# 查询两个数据库的数据

    我目前有一个查询 我正在从两个不同的数据库获取数据 这些数据被附加到一个名为 accountbuys 的列表中 我的第一个表有三个数据条目 3个想要购买股票的帐户 下一张表有 17 个数据点 购买 17 只股票 I am merging t
  • SQL查询获取最后两条记录的DateDiff

    我有一个名为 Event 的表 其中 eventNum 作为主键 日期作为 SQL Server 2008 R2 中的 datetime2 7 我试图获取表中最后两行的日期并以分钟为单位获取差异 这就是我目前所拥有的 Select DATE
  • 与常规 SQL 查询不同,为什么“linq to sql”查询以 FROM 关键字开头?

    为什么 linq to sql 查询以FROM与常规 SQL 查询不同的关键字 LINQ 模仿Logical Query processing在 SQL 中你有 8 SELECT 9 DISTINCT 11 TOP 1 FROM 2 ON
  • 了解涉及 3 个或更多表时 JOIN 的工作原理。 [SQL]

    我想知道是否有人可以帮助我提高对 SQL 中 JOIN 的理解 如果它对问题很重要 我会特别考虑 MS SQL Server 取 3 个表 A B A 通过某些 A AId 与 B 相关 和 C B 通过某些 B BId 与 C 相关 如果
  • 过滤项目来源

    通过此代码 我设置了数据网格的 ItemsSource 不过 我有更多的 wpf 控件来过滤数据网格 例如从时间范围过滤数据网格 我可以为此编写一个新查询 但这似乎没有必要 因为数据已经可用 我只需要过滤它 最好的方法是什么 我能得到的任何
  • SQL 查询结果为字符串(或变量)

    是否可以将SQL查询结果输出到一个字符串或变量中 我的php和mysql不好 假设我有数据库 agents 其中包含列 agent id agent fname agent lname agent dept 使用此查询 sql SELECT
  • 版本控制存储过程/PLSQL?

    有没有一种有效的方法来对用 PL SQL 编写的存储过程进行版本控制 我只提到 PL SQL 因为可能存在特定的工具 任何针对存储过程版本控制的答案都是理想的 在我目前的工作中 团队现在使用以下方法对PL SQL进行版本控制 编译PL SQ
  • 如何将变量设置为触发器 MYSQL 内存储过程的结果?

    我这里有一个小问题 我正在为我的数据库工作创建一个触发器 但我不知道如何在触发器内使用存储过程 我想将过程的结果保存在变量中 然后使用稍后在 IF 比较器上变量 这是我的代码 DELIMITER CREATE TRIGGER insert
  • If Else 条件的 SQLite 语法

    我正在使用 SQLite 数据库 我的表有一个名为 密码 的文本列 早些时候 为了检索我用来执行简单操作的值select from myTable询问 但现在的要求是 如果Password值不是NULL那么我需要将其显示为 是 或 否 它是
  • 对对象集合进行排序[重复]

    这个问题在这里已经有答案了 如果我有一个简单的字符串列表 List
  • 如何限制两个表之间一对多关系中的多个数量?

    我有一个带有两个 MySql 表的 MySQL 数据库 第一个是第一个表 表 A 有一列具有唯一值 从值 从 1 到 n 在第二个表 2 表 B 中 我有两列 在第一个表中我有一个名称 在第二个我的值从 1 到 n 如果我在 中添加一个值
  • 在 Django shell 会话期间获取 SQL 查询计数

    有没有办法打印 Django ORM 在 Django shell 会话期间执行的原始 SQL 查询的数量 Django 调试工具栏已经提供了此类信息 例如 5 QUERIES in 5 83MS但如何从 shell 中获取它并不明显 您可
  • SQLite 中的累积求和值

    我正在尝试在 SQLite 中执行值的累积和 我最初只需要对一列求和并获得代码 SELECT t MyColumn SELECT Sum r KeyColumn1 FROM MyTable as r WHERE r Date lt t Da
  • PostgreSQL 如何对字段上的 b 树索引执行 ORDER BY?

    我有一张桌子bsort CREATE TABLE bsort a int data text Here data可能不完整 换句话说 某些元组可能没有data value 然后我在表上建立一个 B 树索引 CREATE INDEX ON b
  • 从两个表中搜索然后删除

    我有两个包含成员数据的表 与 member id 列链接 我需要搜索所有记录email列以 pl 结尾 然后 我需要为此删除两个表中的所有记录 基于 member id 是否可以通过一条 SQL 语句完成此操作 SELECT member
  • MySQL如何根据字段是否存在来插入新记录或更新字段?

    我正在尝试实现一个评级系统 在数据库表中保留以下两个字段 评级 当前评级 num rates 迄今为止提交的评分数量 UPDATE mytable SET rating rating num rates theRating num rate
  • 基于数组对列表进行排序

    我正在尝试根据字符串数组对自定义列表进行排序 但我失败得很惨 例如它根本没有对列表进行排序 Public class CrateOrder public int Id get set public string Name get set p
  • Mysql为简单频繁查询创建排序索引性能

    我正在处理一个包含大约 400 万条消息条目的 mysql 表 并尝试根据时间戳选择最新的 50 条消息 另一个要求是返回的消息不以固定前缀开头 问题是单个查询大约占用 25 的 cpu 并且最多需要 1 5 秒 该查询经常由多个客户端执行
  • 使用另一个表中的数据查找并替换 MySQL 中的字符串

    我有两个 MySQL 表 我想使用另一个表中的数据查找和替换一个表中的文本字符串 Table texts messages thx guys i think u r great thx again u rock Table dictiona

随机推荐