如何在编写sql查询时不重复自己的操作?

如何在编写sql查询时不重复自己的操作?,sql,.net,Sql,.net,让我们进行这个简单的查询(下面的代码可能不准确) 假设我使用ORM将行映射到库存类,我的函数是 inventory[] get_inventory(int x, int y) 现在让我们假设我需要使用相同查询的额外数据。我想加入一个表,并在该查询上获得两个额外字段 class inventory2 : inventory { string owner_name; long owner_id; } ... inventory2[] get_inventory2(int x, int y) { .

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

假设我使用ORM将行映射到库存类,我的函数是

inventory[] get_inventory(int x, int y)
现在让我们假设我需要使用相同查询的额外数据。我想加入一个表,并在该查询上获得两个额外字段

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之外,我想不出其他方法来实现这一点,希望在更改另一个sql时不要忘记更改其中一个


我怎样才能不重复我自己的话?

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

如果您没有使用为您生成select查询的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也是一个好方法。:-)

您需要将查询更改为使用内部联接,否则您的查询(如编写的)将得到一个新的连接

如果这是针对SQL Server的,您还需要删除
限制20
,并将
前20
放在选择列表中

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

这两个查询甚至不尽相同。第一个查询从单个表中提取数据。编写的第二个查询对两个表执行双重外部(或笛卡尔)联接。即使您已经为联接添加了匹配条件,但仍然缺少防止其成为内部联接所需的语法。内在联结会让你更接近你所说的。我以为那是内在联结。你建议如何重写这个?(即使在sql中不可能不重复我的话)当您有类似于
的内容时,您会怎么做?从aTable中选择a.c1、a.c2、b.c1、b.c2作为内部联接b表作为a.id=b.id上的b
?您推荐吗?我使用的是dapper.net,这很好,但它是一种轻型ORM,用于(快速)将行转换为对象。它与sql生成无关。此外,除非我在名称空间级别这样做,否则我不能完全做到这一点。我要退两门课。我想我可以在这两种情况下返回派生类,但如果我不需要,我宁愿不返回。撇开一个完全不需要这样做的ORM不谈,我也想到了动态SQL……但在维护性方面,由于复杂性而受到损害的想法与一点重复的想法完全相同,这至少有利于提高可读性。我还同意,使用动态过滤器的报告/搜索查询是这条规则的一个例外。@acidzombie24,我个人也喜欢Dapper.net的原始性能。在我们的应用程序中,我们使用了很久以前在内部开发的类似的东西,除了我们在编译时生成所有的类和转换器,所以我们甚至没有初始开销(我们知道我们的数据库不能在没有代码更改的情况下进行更改)。如果你想要一个功能齐全的ORM,那么就选择nHibernate。它将为您提供更多功能,但性能不如预期。对于大多数应用程序来说,这无关紧要——ORM很少成为瓶颈。Dapper.net是为Stackoverflow而设计的。@Zombie 24,关于类问题,您可以通过使用具有特定返回类型的不同公共方法和具有返回父类型的实际实现的私有方法来实现。然后,在您知道的特定类型中,您可以安全地强制转换到更特定的子类型并返回该子类型?如果sqlite是个例外,我想我一直在写糟糕的查询。Sqlite说
旁注:交叉连接的特殊处理。“内部联接”、“联接”和“联接”运算符之间没有区别。它们在SQLite中完全可以互换。“交叉联接”联接运算符产生的结果与“内部联接”、“联接”和“,”运算符相同,但查询优化器的处理方式不同,因为它阻止查询优化器在联接中对表重新排序
,该定义与ANSI标准中的交叉联接非常接近。
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
SELECT TOP 20 a, b, c, o.owner_name, o.id as owner_id 
...