让我们采取这个简单的查询(下面的代码可能不准确)
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之外,我无法想办法做到这一点,并希望当我改变另一个时我不会忘记改变它。
我怎么不重复自己?
答案 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
...