Sqlite Update Select查询 - 引用正在内部Select的Order By子句中更新的表

时间:2016-09-06 13:42:12

标签: sql sqlite

我试图通过select查询的结果更新表中的值。问题是我不允许在最里面的表的Order By子句中引用最外面的表(正在更新的表)(用于选择新值的表)。

假设我有下表:

MustMatch   PreferredMatch  Old         New       
----------  --------------  ----------  ----------
0           Blue            Old blue              
1           Blue            Wrong matc            
0           Red             Unpreferre            
0           Blue            Preferred   

我想填写“Old blue”的“New”栏目。新值必须与旧值不同,但在MustMatch列上匹配。以下查询将执行此操作:

UPDATE t 
SET New = (
    SELECT innerTable.Old 
    FROM t innerTable 
    WHERE innerTable.Old != t.Old 
        AND innerTable.MustMatch = t.MustMatch 
    LIMIT 1
) WHERE Old = "Old blue";

MustMatch   PreferredMatch  Old         New              
----------  --------------  ----------  -----------------
0           Blue            Old blue    Unpreferred match
1           Blue            Wrong matc                   
0           Red             Unpreferre                   
0           Blue            Preferred    

现在,我想添加一个首选项:我想在内部查询中添加ORDER BY innerTable.PreferredMatch = t.PreferredMatch

UPDATE t 
SET New = (
    SELECT innerTable.Old 
    FROM t innerTable 
    WHERE innerTable.Old != t.Old 
        AND innerTable.MustMatch = t.MustMatch 
    ORDER BY innerTable.PreferredMatch = t.PreferredMatch DESC 
    LIMIT 1
) WHERE Old = "Old blue";

这会引发错误Error: no such column: t.PreferredMatch

问题是对t的引用。当我执行

时,Order By子句按预期工作
UPDATE t 
SET New = (
    SELECT innerTable.Old 
    FROM t innerTable 
    WHERE innerTable.Old != t.Old 
        AND innerTable.MustMatch = t.MustMatch 
    ORDER BY innerTable.PreferredMatch = 'Blue' DESC 
    LIMIT 1
) WHERE Old = "Old blue";

MustMatch   PreferredMatch  Old         New            
----------  --------------  ----------  ---------------
0           Blue            Old blue    Preferred match
1           Blue            Wrong matc                 
0           Red             Unpreferre                 
0           Blue            Preferred     

为什么我不允许在Order By子句中使用表t,即使我可以在Where子句中使用它?还有另一种方法可以达到这个目的吗?

3 个答案:

答案 0 :(得分:0)

我很惊讶您的版本不起作用。这是一个强力解决方案:

UPDATE t 
    SET New = COALESCE((SELECT it.Old 
                        FROM t it 
                        WHERE it.Old <> t.Old AND
                              it.MustMatch = t.MustMatch AND
                              it.PreferredMatch = t.PreferredMatch
                        LIMIT 1
                       ),
                       (SELECT it.Old 
                        FROM t it 
                        WHERE it.Old <> t.Old AND
                              it.MustMatch = t.MustMatch AND
                              it.PreferredMatch <> t.PreferredMatch
                        LIMIT 1
                       ))
WHERE Old = 'Old blue';

或者这可能有效:

UPDATE t 
    SET New = (SELECT COALESCE(MAX(CASE WHEN it.PreferredMatch = t.PreferredMatchit.Old 
                                        THEN t.Old
                                   END),
                               MAX(t.Old))
               FROM t it 
               WHERE it.Old <> t.Old AND
                     it.MustMatch = t.MustMatch AND
              );

答案 1 :(得分:0)

如果不是

UPDATE test 
SET New = (
    SELECT innerTable.Old 
    FROM test innerTable 
    WHERE innerTable.Old != test.Old 
        AND innerTable.MustMatch = test.MustMatch 
    ORDER BY innerTable.PreferredMatch = test.PreferredMatch DESC 
    LIMIT 1
) WHERE Old = "Old blue";

你再使用一个级别

UPDATE test 
SET New = (SELECT newValue FROM
    (SELECT innerTable.Old as newValue,
            innerTable.PreferredMatch = test.PreferredMatch as pick
    FROM test innerTable 
    WHERE innerTable.Old != test.Old 
        AND innerTable.MustMatch = test.MustMatch 
    ORDER BY pick DESC 
    LIMIT 1) foo
) WHERE Old = "Old blue";

然后它可以工作(你按顺序使用select中的字段名称,而在select中你可以使用外部表中正在更新的字段)。

恕我直言,这是sqlite中的一个错误 - 没有理由为什么来自外部表的字段可以用在where和select子句中但不能用于order-by。

答案 2 :(得分:0)

请注意,postgresql中的完全相同的运行只是起作用:

var express = require('express');
var app = express();
var firebase = require('firebase');

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/html/index.html');
});

app.get('/welcome', function (req, res) {
  res.sendFile(__dirname + '/html/welcome.html');
});

这真的感觉像sqlite错误 - 在子选择中使用外部字段应该没有区别。