頭を一周できないケースがあるようです。したがって、他の誰かにも役立つ可能性があるクエリへのポインタを見つけることを期待してここに来る。
以下では、結果を返す限り正しく機能するクエリがありますが、ここで示したものと同じであるがOFFSET
がない2番目のクエリが必要で、出力はCOUNT(*)
のみです。すべての行の。
私には2つの目的があります。
COUNT(*)
が同じクエリで返されるようにクエリを記述します。実際、私は優れた SQL SERVER – OFFSET/FETCH NEXT(ページング)から合計行数を取得する方法 などのヘルプピースをさまざまな方法で検討してきましたが、別のピースがあります。 ..OVER(PARTITION BY
とINDEX SCAN
を生成するように見えるため、ウィンドウ関数(INDEX SEEK
など)またはよりパフォーマンスの高い方法で結合を書き換えます。実際のクエリはWHERE
の部分がもう少し複雑ですが、クエリがもう少し単純でCOUNT
とMAX
は、外部クエリと同時に使用できます。これでも勝利ですが、全体的なCOUNT
を組み合わせることでさらに大きくなります。多分私は現在噛んでいるよりも少しだけ噛んでいるのかもしれませんが、一方で、何かを学ぶ機会があるかもしれません。
ここにテーブルとデータがあります
CREATE TABLE Temp
(
Id INT NOT NULL PRIMARY KEY,
Created INT NOT NULL,
ParentId INT,
SomeInfo INT NOT NULL,
GroupId INT NOT NULL
CONSTRAINT FK_Temp FOREIGN KEY(ParentId) REFERENCES Temp(Id)
);
-- Some root levels nodes.
INSERT INTO Temp VALUES(1, 1, NULL, 1, 1);
INSERT INTO Temp VALUES(2, 2, NULL, 2, 2);
INSERT INTO Temp VALUES(3, 3, NULL, 1, 3);
INSERT INTO Temp VALUES(13, 13, NULL, 1, 1);
-- First order child nodes.
INSERT INTO Temp VALUES(4, 4, 1, 2, 1);
INSERT INTO Temp VALUES(5, 5, 2, 1, 2);
INSERT INTO Temp VALUES(6, 6, 3, 2, 3);
-- Second order child nodes.
INSERT INTO Temp VALUES(7, 7, 4, 1, 1);
INSERT INTO Temp VALUES(8, 8, 5, 2, 2);
INSERT INTO Temp VALUES(9, 9, 6, 1, 3);
SELECT
Id,
newestTable.SomeInfo,
newestTable.Created,
CASE WHEN newestTable.RootCount > 1 THEN 1 ELSE 0 END AS IsMulti
FROM
Temp as originalTable
INNER JOIN
(
SELECT
SomeInfo,
Max(Created) AS Created,
Count(*) AS RootCount
FROM
Temp
WHERE ParentId IS NULL AND GroupId = 1
GROUP BY SomeInfo
) AS newestTable ON originalTable.SomeInfo = newestTable.SomeInfo AND originalTable.Created = newestTable.Created
/*WHERE
(
originalTable.SomeInfo = 1
)*/
ORDER BY newestTable.Created ASC
OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY;
追伸また Postgresqlのサブクエリで使用される完全なテーブルでのグループ化を回避するために、サブクエリで外部制限オフセットとフィルターを適用する方法 は興味深いように見えます。
<編集:
のように見えます
SELECT
Id,
SomeInfo,
GroupId,
ParentId,
MAX(Created) OVER(PARTITION BY SomeInfo) AS Created,
COUNT(Id) OVER(PARTITION BY SomeInfo) AS RootCount,
CASE WHEN COUNT(Id) OVER(PARTITION BY SomeInfo) > 1 THEN 1 ELSE 0 END AS IsMulti
FROM
Temp
WHERE
(
GroupId = 1 AND ParentId IS NULL
)
ORDER BY Created ASC
OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY;
そこに近づきます。しかし、問題は、2つの結果行が存在することです。これは、元のINNER JOIN
がTemp
に結合して1行に間引いたためと思われます。ウィンドウ処理の前または後に何らかの方法で条件を適用して、元のクエリにより厳密に一致させる方法はあるのでしょうか。 (そして、これは明確に言うと同じクエリではありません。データが非常に少ないため、クエリは互いに近くにあるように見えます。)
だから私にはあなたが欠けているのは「各インスタンスのトップCreated
レコードのみを返す」のようです。したがって、すべての行を取得していて、その最上位のCreated
値が同じSomeInfo
レコードに対するものである場合。残念ながら、MAX(Created) = Created
を基本のWHERE
句に追加することはできません。
全体をCTE
でラップするだけの場合は、WHERE
にMAX(Created) = Created
を追加するだけで、探しているものを取得できます(私が思うにCTE
はすべての答えです)。
WITH CTE (ID, SomeInfo, GroupID, ParentID, Created, MaxCreated, RootCount, IsMulti)
AS
(
SELECT
Id,
SomeInfo,
GroupId,
ParentId,
Created,
MAX(Created) OVER(PARTITION BY SomeInfo) AS MaxCreated,
COUNT(Id) OVER(PARTITION BY SomeInfo) AS RootCount,
CASE WHEN COUNT(Id) OVER(PARTITION BY SomeInfo) > 1 THEN 1 ELSE 0 END AS IsMulti
FROM
Temp
)
SELECT ID, SomeInfo, GroupID, ParentID, MaxCreated AS Created, RootCount, IsMulti
FROM CTE
WHERE
(
GroupId = 1
AND ParentId IS NULL
AND Created = MaxCreated
)
ORDER BY MaxCreated ASC
OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY;
私の簡単なテストでは、同じ実行プランがあり、追加の実行時間はかかりません(下記の実行プランを参照)。 (これは小さな結果セットなので、おそらくまだテストする必要があります。)
うまくいけば、それがあなたが探しているものの多くです。