在编写SQL查询时如何不重复自己?

时间:2014-03-14 04:56:47

标签: sql .net

让我们采取这个简单的查询(下面的代码可能不准确)

select a, b, c from inventory where x=:x AND y=:y limit 20

假设我使用ORM将行映射到库存类,我的功能就是这个

inventory[] get_inventory(int x, int y)

现在假设我需要使用SAME查询来获取额外数据。我想加入一个表,并在该查询之上获得2个额外字段

class inventory2 : inventory { string owner_name; long owner_id; }
...
inventory2[] get_inventory2(int x, int y) {
...
select a, b, c, o.owner_name, o.id as owner_id from inventory i join owner o on i.owner=o.id where x=:x AND y=:y limit 20
CHANGES         ^----------------------------^                  ^--------------------------^

这应该是各种方式的相同查询。我只想要额外的字段。除了复制/粘贴sql之外,我无法想办法做到这一点,并希望当我改变另一个时我不会忘记改变它。

我怎么不重复自己?

3 个答案:

答案 0 :(得分:1)

无法共享选择列表,因为这是两个不同的查询,并且都需要自己的字段列表来进行选择。

答案 1 :(得分:1)

如果您没有使用为您生成选择查询的ORM工具,请不要尝试过度减少重复。

可以通过将查询分成片段然后根据您添加所需片段的标志来实现,例如:

var sql = "SELECT A, B, C";

if (test1) sql += ", D, E, F";
if (test2) sql += ", G, H, I";

sql += " FROM inventory ";

if (test1) sql += "inner join .. ";
if (test2) sql += "inner join .. ";

这确实有效,在某些情况下(特别是使用非常动态的过滤器进行报告)我自己也这样做了,但通常情况下更好的是复制并具有可读的单独查询,然后是一堆条件使其无法维护,更难以测试,并且可以根据条件的组合轻松地生成错误的查询。

我们的一位开发人员尝试使用SQL预解析器来嵌入条件。我们有这样的SQL:

SELECT
    a, b, c
    , d, e, f   /*? test1 */
    , g, h, i   /*? test2 */
FROM
    Table1
        INNER JOIN Table2 ON Table1.ID = Table2.FKID    /*? test1 */
        INNER JOIN Table3 ON Table1.ID = Table3.FKID    /*? test */

这比传统的动态SQL更好,它更具可读性,但它仍然不是很好,仍然可以很容易搞砸和产品不良查询,具体取决于条件的组合。我们最终根本没有在生产中使用它。

所有这一切,一个好的ORM也是一个很好的方式。 : - )

答案 2 :(得分:1)

您需要更改查询以使用INNER JOIN,否则您的查询(如编写的)将获得Cartesian join resultset

SELECT a, b, c, o.owner_name, o.id as owner_id 
FROM inventory i INNER JOIN owner o ON i.owner=o.id 
WHERE x=:x AND y=:y LIMIT 20

如果这是针对SQL Server的,您还需要删除LIMIT 20并将TOP 20放入选择列表中。

SELECT TOP 20 a, b, c, o.owner_name, o.id as owner_id 
...