您可以使用 SQL 来完成此操作,无需为其编写额外的代码

2025-05-24

您可以使用 SQL 来完成此操作,无需为其编写额外的代码

“SQL、Lisp 和 Haskell 是我见过的仅有的几种编程语言,人们花在思考上的时间比打字的时间还多。”—— Philip Greenspun

即使我们软件工程师考虑的不仅仅是输入 SQL(结构化查询语言),我们也只是将其用作提取数据的一种方式。

我们通常不会利用 SQL 的数据操作功能并在代码中进行必要的更改。

这在从事 Web 应用的软件工程师中相当普遍。我们忽略的另一件事是,如果我们直接用 SQL 进行操作,那么提取的数据对于任何编程语言来说都是相同的格式。这篇文章旨在让你了解 SQL 的强大功能,你可能知道这些,但通常不会用到。

茶灯图片来自 [Pixabay](https://pixabay.com/en/tea-lights-candles-light-prayer-2223898/)茶灯图片来自Pixabay

TLDR;

使用 SQL 进行数学运算,例如求和、求平均值等。利用 SQL 对一对多关系值进行分组,例如获取产品类别。利用 SQL 进行字符串操作,例如使用 CONCAT_WS 连接名字和姓氏。利用 SQL 按自定义优先级公式进行排序。示例如下……

示例

通过一个例子来解释 SQL 的强大功能会更容易一些。下面是一个退款微服务的基本架构,包含 MYSQL 中的两张表:

有 2 笔退款和 7 笔相关付款作为示例数据

一些假设

对于退款微服务示例模式和应用程序,做出以下假设:

  1. 退款微服务和数据结构存储 fk_item(订购/交付商品的 id),但它不是硬外键。

  2. 可以现金或信用额度退还商品的已付金额。

  3. 只要余额足以支付每次现金和信用额度的退款要求,商品可以多次退款。例如,某件商品以现金和信用额度各支付了 50 美元,则可以进行两次退款,每次 20 美元现金和 20 美元信用额度。因此,完成这些交易后,该商品的余额将为 10 美元现金和 10 美元信用额度(50 美元 - 20 美元 - 20 美元)。

  4. 每笔退款可以包含多笔付款。每笔付款可以是现金或信用卡。

  5. 所有金额都以美分为单位存储,因此它们是整数。

现在让我们使用一些 SQL 功能。您可以在SQL Fiddle上找到运行相关查询的示例

使用 SQL 进行计算

作为软件工程师,假设我们需要查找某件商品的退款总额和信用额度,我们会怎么做?我们会运行如下代码:

SELECT fk_item, fk_refund, amount, is_cash 
FROM payment WHERE fk_item=2001;
Enter fullscreen mode Exit fullscreen mode

使用当前数据,它将提供如下所示的 3 行:

对于这三行,我们将循环遍历它们。如果是现金,则将其累加到 cashBalance 变量中;如果不是,则将其加总到 creditBalance 变量中。与其这样,不如用 SQL 语句来做,这样会更简单(可能也更快):

SELECT fk_item, SUM(amount) AS total_paid, IF(is_cash = 1, 'cash', 'credit') as type 
FROM payment WHERE fk_item = 2001 GROUP BY fk_item, is_cash;
Enter fullscreen mode Exit fullscreen mode

导致:

现在结果很简单,如果您需要该商品的总退款金额,只需将 GROUP BY 更改为 fk_item 即可。对于 2 条和 3 条记录,这不会显得太重要。如果该商品有 20 条退款记录,那么第一个使用循环的解决方案会编写更多代码,且没有任何好处。与 sum 类似,其他 SQL 函数也可以使用。简单的数学运算,例如sum、multiply、average等,用 SQL 就可以轻松完成。这意味着不再需要循环。

使用 GROUP_CONCAT 获取相关的 1:m 关系值

组连接是 SQL 数据库中一项强大的操作。当你需要从一对多关系中获取数据时,它非常有用。例如,你想获取一篇博文的所有标签,或者你想获取一个产品的所有类别。就这个退款示例而言,一件商品可以多次退款。因此,我们将获取与该商品 ID 关联的所有退款。为此,我们只需运行一个查询,并且在代码中不包含任何循环即可获得结果,如下所示:

SELECT fk_item, GROUP_CONCAT(DISTINCT fk_refund) refund_ids 
FROM payment WHERE fk_item = 2001;
Enter fullscreen mode Exit fullscreen mode

其结果是:

现在我们知道商品 2001 已退款两次,总共退款 2 次。使用 可以轻松扩展退款 ID,并继续进行任何相关操作。

字符串操作

SQL 中可以完成许多字符串操作任务,例如子字符串、连接、更改大小写和字符串比较。通过这个例子,我将展示 CONCAT_WS 的用法。它是用分隔符连接起来的。它也可以用于选择例如 first_name 和 last_name 之间带有空格的情况。

如果有可选的中间名,COALESCE 可以与 CONCAT_WS 一起使用。这值得您探索 :)。

在此示例中,我将选择 refund_nr 及其相关原因:

SELECT CONCAT_WS("-", refund_nr, reason) AS refund_nr_with_reason 
FROM refund;
Enter fullscreen mode Exit fullscreen mode

导致:

例如,如果需要在信用票据文件中显示这些值,则无需额外的代码来再次连接这些值。SQL 使这一切变得更加简单。

使用自定义公式排序

所有软件工程师都知道可以基于列进行排序。但是,如果给你一个自定义的优先级公式来排序,你会怎么做?很可能又要回到代码循环排序了。所以,让我们为上面的例子设置优先级公式规则:

  1. 高级客户退款享有最高优先级(我们将其优先级设为 9999999999)

  2. 除高级客户外,现金退款优先获得金额 * 25,信用额度为金额 * 20。

根据上述规则,优先处理高级客户和50000(以美分为单位)以上的优先退款。之后再处理其他退款。我们来看看优先退款的具体情况:

SELECT r.refund_nr, r.reason, p.fk_item, p.amount, p.is_cash,
IF(p.premium_customer = 1, 9999999999, p.amount * (IF(is_cash = 1, 25, 20))) AS priority 
FROM refund AS r INNER JOIN payment AS p ON r.id = p.fk_refund 
HAVING priority > 50000 
ORDER BY priority DESC
Enter fullscreen mode Exit fullscreen mode

结果如下:

在 SQL 中正确使用 IF 语句,通过自定义优先级公式进行排序比在代码中使用循环要容易得多。请注意,即使是较小的金额,例如 7.5(750 美分)和 9.0(900 美分),也会获得最高优先级,因为这些退款金额与高级客户相关。

使用 SQL 的超能力让您作为软件工程师的生活变得更轻松。

您可以使用该示例并在SQL fiddle上运行您的查询。

结论

SQL 还有其他技巧可以帮助你成为一名软件工程师。比如,在 UPDATE 语句中使用 ON DUPLICATE KEY UPDATE 语句进行 INSERT 操作。每当你想用循环代码对从数据库中提取的数据进行操作时,请三思。这个故事的主要内容是:

利用 SQL 的强大功能来减少代码编写,因为“最好的代码是从未编写的代码”。如果没有编写,就无需维护。


原文刊登于geshan.com.np

文章来源:https://dev.to/geshan/you-can-do-it-in-sql-stop-writing-extra-code-for-it-lok
PREV
JSON Web Tokens (JWT) vs. SessionID 🔐 ? explained in 2 mins What's the Difference? Why JWT? Nice! Why not JWT Everything then? So should I use JWT for my next project?
NEXT
成长为一名开发者——来自 Dan Heller 的建议