2016-05-20 21 views
1

に代わり、完全な結合表のメインテーブルの上にのみ集約することで、私は5つのテーブルUSER_ATTRIBQUESTION_MAINREPLY_MAINCATEGORY_MAINQSTN_CATG次のように相互に関連があります。Sequelize GROUP参加

m.QUESTION_MAIN.belongsTo(m.USER_ATTRIB, { foreignKey: 'POSTER_I', targetKey: 'USER_I'}); 
m.QUESTION_MAIN.hasMany(m.REPLY_MAIN, { foreignKey: 'QSTN_I' }); 
m.QUESTION_MAIN.belongsToMany(m.CATEGORY_MAIN, { through: m.QSTN_CATG, foreignKey: 'QSTN_I' }); 
m.QUESTION_MAIN.hasMany(m.QSTN_CATG, { foreignKey: 'QSTN_I' }); 

を私がしたいです質問の詳細については、QUESTION_MAINの質問を実行してください。

SELECT `QUESTION_MAIN`.* 
     ,`USER_ATTRIB`.`USERATTRIB_ID` AS `USER_ATTRIB.USERATTRIB_ID` 
     ,`USER_ATTRIB`.`USER_NAME` AS `USER_ATTRIB.USER_NAME` 
     ,`QSTN_CATGs`.`QSTN_CATG_ID` AS `QSTN_CATGs.QSTN_CATG_ID`, 
     ,`QSTN_CATGs`.`CATG_I` AS `QSTN_CATGs.QSTN_CATG_I` 
     ,`REPLY_MAINs`.`REPLY_ID` AS `REPLY_MAINs.REPLY_ID` 
     , COUNT(`REPLY_MAINs`.`QSTN_I`) AS `REPLY_MAINs.REPLY_COUNT` 
FROM (
     SELECT `QUESTION_MAIN`.`QUESTION_ID` 
       , (6371 * acos(cos(radians(13.0508629)) * cos(radians(QSTN_LOC_LAT)) * cos(radians(QSTN_LOC_LONG) - radians(77.6092108)) + sin(radians(13.0508629)) * sin(radians(QSTN_LOC_LAT)))) AS `DISTANCE` 
     FROM `QUESTION_MAIN` AS `QUESTION_MAIN` 
     WHERE (
       SELECT `QSTN_I` 
       FROM `QSTN_CATG` AS `QSTN_CATG` 
       WHERE (`QSTN_CATG`.`QSTN_I` = `QUESTION_MAIN`.`QUESTION_ID`) LIMIT 1 
       ) IS NOT NULL 
     HAVING `DISTANCE` < 5 
     ORDER BY `QUESTION_MAIN`.`CREATED` DESC LIMIT 3 
     ) AS `QUESTION_MAIN` 
LEFT OUTER JOIN `USER_ATTRIB` AS `USER_ATTRIB` ON `QUESTION_MAIN`.`POSTER_I` = `USER_ATTRIB`.`USER_I` 
INNER JOIN `QSTN_CATG` AS `QSTN_CATGs` ON `QUESTION_MAIN`.`QUESTION_ID` = `QSTN_CATGs`.`QSTN_I` 
LEFT OUTER JOIN `REPLY_MAIN` AS `REPLY_MAINs` ON `QUESTION_MAIN`.`QUESTION_ID` = `REPLY_MAINs`.`QSTN_I` 
       AND `REPLY_MAINs`.`REPLY_STATUS` = 200 
GROUP BY `QUESTION_ID` 
ORDER BY `QUESTION_MAIN`.`CREATED` DESC; 

これはSequelizeです:必要なディテールの一つは、私が実行したい複合クエリーがある

​​3210

で照会することができる質問に対する回答の数であり、そのクエリを作成します

QUESTION_MAIN.findAll({ 
attributes:['QUESTION_ID', 'POSTER_I', 
    ['(6371 * acos(' 
        + 'cos(radians('+qstnFeedRequest.qstnLocLat+')) ' 
        + '* cos(radians(QSTN_LOC_LAT)) ' 
        + '* cos(radians(QSTN_LOC_LONG) - radians('+ qstnFeedRequest.qstnLocLong+')) ' 
        + '+ sin(radians('+qstnFeedRequest.qstnLocLat+')) ' 
        + '* sin(radians(QSTN_LOC_LAT))) ' 
    + ')', 'DISTANCE' 
    ] 
], 
include: [ 
    { model: USER_ATTRIB, 
    attributes:['USER_NAME'] 
    }, 
    { model: QSTN_CATG, 
    attributes: [['CATG_I', 'QSTN_CATG_I']], 
    where: qstnCatgWhereClause 
    }, 
    { model: REPLY_MAIN, 
    attributes: [[sequelize.fn('COUNT', sequelize.col('REPLY_MAINs.QSTN_I')), 'REPLY_COUNT']], 
    where: {REPLY_STATUS: 200}, 
    required: false 
    } 
], 
having:{ 'DISTANCE' : {$lt: 5} }, 
where: whereClause, 
group: ['QUESTION_ID'], 
limit: qstnFeedRequest.limit 
}) 

のTh電子の問題はGROUP BY句がない全体的に、内部の内部クエリを適用されていることですが参加:

SELECT `QUESTION_MAIN`.*, 
    ... 
FROM (
    SELECT `QUESTION_MAIN`.`QUESTION_ID`, 
    ... 
    HAVING `DISTANCE` < 5 
    GROUP BY `QUESTION_ID` -- This should go outside 
    ORDER BY `QUESTION_MAIN`.`CREATED` DESC LIMIT 3 
    ) AS `QUESTION_MAIN` 
LEFT OUTER JOIN `USER_ATTRIB` ... 
ORDER BY `QUESTION_MAIN`.`CREATED` DESC; 

これは、カウントに間違った凝集を引き起こしています。私が何を試しても、GROUP BY節を内側のクエリから取り出すことができません。

メインテーブルだけでなく、結合全体にグループ化するにはどうすればよいですか?

+0

UPDATE:生成されたSQLが原因になるのOF_ _kind制限のサブクエリを持っています1:M([ここで述べたように](https://github.com/sequelize/sequelize/issues/1640#issuecomment-40706942)のように)の文脈では意味がありません。制限を削除すると、サブクエリが削除され、結合全体でグループ化され、問題が解決しました。今、私は制限を保持し、サブクエリの外にGROUP BYを押してください。どうやってやるの? –

答えて

1

ウェブの半分を探索した後、私は最終的に解決策を見つけました。

link is in the commentのスレッドで述べたように、結合外の制限を持つ1:Mクエリを作成することは非効率的です。したがって、Sequelizeは、1:1およびM:関係のクエリを分離します。つまり、separate: trueというプロパティが1:Mテーブルのインクルードステートメントに設定されています。

コードブレークのテーブルの結合列が属性に含まれていない場合:

も、この後、問題がいくつかあります。

Sequelizeは、内側の表の外側のhaving句も適用します。それを防ぐために、私はインクルードにhavingというステートメントを追加しました。

これは、修正後の私の最後のSequelizeです:これはセーブ

QUESTION_MAIN.findAll({ 
attributes:['QUESTION_ID', 'POSTER_I', 
    ['(6371 * acos(' 
        + 'cos(radians('+qstnFeedRequest.qstnLocLat+')) ' 
        + '* cos(radians(QSTN_LOC_LAT)) ' 
        + '* cos(radians(QSTN_LOC_LONG) - radians('+ qstnFeedRequest.qstnLocLong+')) ' 
        + '+ sin(radians('+qstnFeedRequest.qstnLocLat+')) ' 
        + '* sin(radians(QSTN_LOC_LAT))) ' 
    + ')', 'DISTANCE' 
    ] 
], 
include: [ 
    { model: USER_ATTRIB, 
    attributes:['USER_NAME'] 
    }, 
    { model: QSTN_CATG, 
    attributes: [['CATG_I', 'QSTN_CATG_I']], 
    where: qstnCatgWhereClause 
    }, 
    { model: REPLY_MAIN, //this is the 1:M table 
    attributes: ['QSTN_I', [sequelize.fn('COUNT', sequelize.col('REPLY_MAIN.QSTN_I')), 'REPLY_COUNT']], 
    //QSTN_I is the column joining QUESTION_MAIN and REPLY_MAIN. Not including this in the attributes throws an error 
    where: {REPLY_STATUS: 200}, 
    group: ['QSTN_I'], //grouping it in this query instead of the main query 
    separate: true,//the culprit 
    having: {'REPLY_COUNT': {$ne: null}}, //this is a dummy having clause which always returns true. This is added to stop the outer having clause being applied to the inner query 
    required: false 
    } 
], 
having:{ 'DISTANCE' : {$lt: 5} }, 
where: whereClause, 
limit: qstnFeedRequest.limit 
}) 

希望は誰かの2日間の時間