0

私は次のようなことをしようとしています。その人の最も古い犬の名前も含む人のレコードを返す必要があります (人が 1 匹以上の犬を飼っている場合)。以下のクエリはNULLdogName. Top 1(確認したところ、有効なデータがあります)結合クエリのandOrder byの部分を削除すると、有効なdogNameが返されますが、「最も古い」犬は返されません。TOP 1and を追加するとOrderByNULL が返されるのはなぜですか?

SELECT
    pt.firstName [FirstName],
    pt.lastName [LastName],
    joinQuery.dogName [dogName]
FROM dbo.PersonTable pt
LEFT OUTER JOIN 
    (
        SELECT
            TOP 1
            dt.dogName [dogName],
            dt.dogAge  [dogAge]
        FROM
            DogTable dt
        ORDER BY dt.dogAge
    ) joinQuery ON joinQuery.PersonId = pt.Id
WHERE
    pt.firstName = 'john'

注: これは、フォーラムに投稿することを許可されていないクエリに似たクエリです。

また、私は決して専門家ではないので、この問題を間違って解決しようとしている可能性があります。前もって感謝します。

4

7 に答える 7

1

結合はまったく必要ありません。

SELECT pt.firstname               [FirstName], 
       pt.lastname                [LastName], 
       (SELECT TOP 1 dt.dogname 
        FROM   dogtable dt 
        WHERE  dt.personid = pt.id 
        ORDER  BY dt.dogage DESC) AS [dogName] 
FROM   dbo.persontable pt 
WHERE  pt.firstname = 'john' 

最も古い犬は であることに注意してくださいORDER BY dt.dogage DESC

于 2013-06-26T13:01:01.620 に答える
0

TOPandを捨てて、派手な SQL ( 、など)ORDER BYを使用しないでください。このように、単純な古いSQLを使用するだけです...PARTITIONSRANK

SELECT
    pt.firstName [FirstName],
    pt.lastName [LastName],
    joinQuery.dogName [dogName]
FROM dbo.PersonTable pt
LEFT OUTER JOIN dbo.DogTable joinQuery ON joinQuery.PersonId = pt.id
WHERE joinQuery.dogAge = (SELECT MAX(dt.dogAge)
                          FROM DogTable dt WHERE dt.PersonId = pt.id)
AND pt.firstName = 'john'
于 2013-06-26T13:08:10.247 に答える
0

あなたの句には末尾のキーワードORDER BYが必要なようです。DESCあなたが指摘したように、「最年長の犬」を取得したかったのです。

于 2013-06-26T12:59:19.360 に答える
0

クエリが NULL を返した理由は、personID ごとに 1 匹の犬ではなく、テーブルから 1 匹の犬を選んでいたためです。値を返すつもりはありませんでした。最初に PersonID ごとの結果が必要です。次に、関心のある人のみに制限します。

ROW_NUMBER()orを使用するRANK()と、次のような問題に適したソリューションになります。

SELECT
    pt.firstName [FirstName],
    pt.lastName [LastName],
    pet.dogName [dogName]
FROM dbo.PersonTable pt
LEFT JOIN 
    (
        SELECT dogName [dogName],dogAge  [dogAge], PersonID, ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY dogage DESC) DogRank
        FROM DogTable
    ) pet ON pet.PersonId = pt.Id
     AND pet.DogRank = 1
WHERE
    pt.firstName = 'john'

1 人が 6 歳の犬を複数飼っている場合は、両方の犬を返却するRANK()代わりに使用できます。ROW_NUMBER()そのうちの 1 つだけが必要な場合は、そのまま使用してROW_NUMBER()ください。

于 2013-06-26T13:02:49.327 に答える
0

別の方法は、を使用することAPPLYです。OUTER APPLY外部結合にCROSS APPLY対応し、内部結合に対応します。見る

http://www.mssqltips.com/sqlservertip/1958/sql-server-cross-apply-and-outer-apply/

http://technet.microsoft.com/en-us/library/ms175156%28v=sql.105%29.aspx

SELECT
    pt.firstName [FirstName],
    pt.lastName [LastName],
    joinQuery.dogName [dogName]
FROM dbo.PersonTable pt
OUTER APPLY
    (
        SELECT
            TOP 1
            dt.dogName [dogName],
            dt.dogAge  [dogAge]
        FROM
            DogTable dt
        WHERE dt.PersonId = pt.Id
        ORDER BY dt.dogAge
    ) joinQuery
WHERE
    pt.firstName = 'john'
于 2013-06-26T13:14:20.103 に答える
0

クエリが無効です。から選択されていない列で結合しています。また、関数を使用するか使用DogTableできる最も古いものが必要な場合。order by descmax

SELECT
    pt.firstName [FirstName],
    pt.lastName [LastName],
    joinQuery.dogName [dogName]
FROM dbo.PersonTable pt
LEFT OUTER JOIN 
    (
        SELECT
            TOP 1
            dt.PersonId,
            dt.dogName [dogName],
            dt.dogAge  [dogAge]
        FROM
            DogTable dt
        ORDER BY dt.dogAge
    ) joinQuery ON joinQuery.PersonId = pt.Id
WHERE
    pt.firstName = 'john'
于 2013-06-26T13:01:10.497 に答える
0

私には問題ないように見えますが、この状況ではおそらく Rank() Over() を検討するでしょう

この場合は遅くなるかもしれませんが

于 2013-06-26T13:00:19.167 に答える