4

每当我们面前有任何查询的描述时,我们都会尝试应用启发式和头脑风暴来构建查询。

是否有任何系统的分步或数学方法来从给定的人类可读描述构造 SQL 查询?

例如,如何确定,SQL 查询是否需要联接而不是子查询,是否需要 group by,是否需要 IN 子句等......

例如,学习数字电子学的人都会知道卡诺图或 Quin McClausky 方法等方法。这些是简化数字逻辑的一些系统方法。

如果有这样的方法来手动分析sql查询以避免每次都集思广益?

4

2 回答 2

3

是否有任何系统的分步或数学方法来从给定的人类可读描述构造 SQL 查询?

就在这里。

事实证明,自然语言表达式和逻辑表达式以及关系代数表达式和 SQL 表达式(后两者的混合体)以一种相当直接的方式对应。(以下是没有重复的行和没有空值。)

每个表(基础或查询结果)都有一个关联的谓词——一种由列名参数化的自然语言填充(命名)空白语句模板。

[liker] likes [liked]

一个表包含每一行,使用该行的列值来填充(命名的)空白,做出一个真实的陈述,即命题。这是一个包含该谓词及其行的命题的表:

liker  | liked
--------------
Bob    | Dex    /* Bob likes Dex */
Bob    | Alice  /* Bob likes Alice */
Alice  | Carol  /* Alice likes Carol */

用表中一行的值填充谓词的每个命题都是真的。并且用不在表中的行中的值填充谓词的每个命题都是错误的。这是该表的内容:

/*
    Alice likes Carol
AND NOT Alice likes Alice
AND NOT Alice likes Bob
AND NOT Alice likes Dex
AND NOT Alice likes Ed
...
AND Bob likes Alice
AND Bob likes Dex
AND NOT Bob likes Bob
AND NOT Bob likes Carol
AND NOT Bob likes Ed
...
AND NOT Carol likes Alice
...
AND NOT Dex likes Alice
...
AND NOT Ed likes Alice
...
*/   

DBA 为每个基表提供谓词。表声明的 SQL 语法很像给定谓词的自然语言版本的传统逻辑简写。这是一个保存我们值的基表的声明:

/* (person, liked) rows where [liker] likes [liked] */
/* (person, liked) rows where Likes(liker, liked) */
CREATE TABLE Likes (
    liker ...,
    liked ...
);

SQL 查询(子)表达式将参数表值转换为一个新表值,该表值包含从新谓词中生成真实语句的行。根据(子)表达式的关系/表运算符,新表谓词可以用参数表谓词表示。查询是一个 SQL 表达式,其谓词是我们想要的行表的谓词。

当我们给一个表 & (可能是隐式的)别名A来连接时,运算符作用于一个值 & 谓词,就像表的一样,但列重命名为 from C,...to A.C,...。然后

  • R , S&R CROSS JOIN S是行the predicate of R AND the predicate of S

  • R INNER JOIN S ON condition是行在哪里the predicate of R AND the predicate of S AND condition

  • R LEFT JOIN S ON condition是其中的行(对于仅 S 列 S1,...)

        the predicate of R AND the predicate of S AND condition
    OR
            the predicate of R
        AND NOT FOR SOME values for S1,... [the predicate of S AND condition]
        AND S1 IS NULL AND ...
    
  • R WHERE condition是行在哪里the predicate of R AND condition

  • SELECT DISTINCT A.C AS D,... FROM R(可能带有隐式A.和/或隐式AS D)是其中的行

    • FOR SOME values for A.*,... [A.C=D AND ... AND the predicate of R](这可能不那么紧凑,但看起来更像 SQL。)
    • 如果没有删除的列,则the predicate of R替换A.C,...D,...
    • 如果有被删除的列,FOR SOME values for被删除的列被[ the predicate of R替换A.C,...D,... ]
  • (X,...) IN (R)方法

    • the predicate of R用列C,...替换X,...
    • (X,...) IN R

示例:(人,喜欢)行的自然语言,其中 [人] 是鲍勃,鲍勃喜欢喜欢 [喜欢] 但不喜欢 Ed 的人:

/* (person, liked) rows where
FOR SOME value for x,
        [person] likes [x]
    and [x] likes [liked]
    and [person] = 'Bob'
    and not [x] likes 'Ed'
*/

使用速记谓词重写:

/* (person, liked) rows where
FOR SOME value for x,
        Likes(person, x)
    AND Likes(x, liked)
    AND person = 'Bob'
    AND NOT Likes(x, 'Ed')
*/

仅使用基表和别名表的速记谓词重写:

/* (person, liked) rows where
FOR SOME values for l1.*, l2.*,
        person = l1.liker AND liked = l2.liked
    AND Likes(l1.liker, l1.liked)
    AND Likes(l2.liker, l2.liked)
    AND l1.liked = l2.liker
    AND person = 'Bob'
    AND NOT (l1.liked, 'Ed') IN Likes
*/

用 SQL 重写:

SELECT DISTINCT l1.liker AS person, l2.liked AS liked
    /* (l1.liker, l1.liked, l2.liker, l2.liked) rows where
        Likes(l1.liker, l1.liked)
    AND Likes(l2.liker, l2.liked)
    AND l1.liked = l2.liker
    AND l1.liker = 'Bob'
    AND NOT (l1.liked, 'Ed') IN Likes
    */
FROM Likes l1
INNER JOIN Likes l2
ON l1.liked = l2.liker
WHERE l1.liker = 'Bob'
AND NOT (l1.liked, 'Ed') IN (SELECT * FROM Likes)

相似地,

  • R UNION CORRESPONDING S是行在哪里the predicate of R OR the predicate of R

  • R UNION S是行在哪里the predicate of R OR the predicate we get by replacing the columns of S by the columns of R in the predicate of R

  • VALUES (X,...), ...C,...是行,其中C = X AND ... OR ...

例子:

/* (person) rows where
    FOR SOME value for liked, Likes(person, liked)
OR  person = 'Bob'
*/

    SELECT liker AS person
    FROM Likes
UNION
    VALUES ('Bob')

因此,如果我们根据给定的基表自然语言语句模板来表达我们想要的行,这些行使真或假(返回或不返回),那么我们可以转换为 SQL 查询,这些查询是逻辑速记和运算符和/或表名的嵌套& 运营商。然后 DBMS 可以完全转换为表来计算使我们的谓词为真的行。

请参阅如何从另一个 SQL 表中获取两个不同列的匹配数据:Inner Join 和/或 Union?重新将其应用于 SQL。(另一个自加入。)有关自然语言短语的更多信息,
请参阅银行场景的关系代数。(在关系代数上下文中。)
请参阅关系代数中的 Null 以获取关系查询的另一个介绍。

于 2015-11-27T07:20:02.223 回答
1

这是我在非分组查询中所做的:

FROM我将我希望在表中每行接收零个或一个输出行的表放入子句。通常,您想要“具有特定属性的所有客户”之类的内容。然后,客户表进入FROM子句。

使用连接来添加列和过滤行。联接不应重复行。连接应该找到零或一行,永远不会更多。这使它非常直观,因为您可以说“连接添加列并过滤掉一些行”。

如果连接可以替换子查询,则应避免子查询。连接看起来更好,更通用并且通常更有效(由于常见的查询优化器弱点)。

如何使用WHERE和预测很容易。

于 2015-11-26T21:39:50.627 回答