質問

私は10年の大半のためにSQL Serverで作業しており、このグループ化(またはパーティション、またはランキング...答えが何であるかわかりません!)は私を困惑させています。簡単なものであるべきだと感じています。私の問題を一般化します:

私には3人の従業員がいるとしましょう(彼らが辞めるか何かを心配しないでください...常に3人がいる)、そして私は彼らの給与を毎月分配する方法に遅れを取っています。

Month   Employee  PercentOfTotal
--------------------------------
1       Alice     25%
1       Barbara   65%
1       Claire    10%

2       Alice     25%
2       Barbara   50%
2       Claire    25%

3       Alice     25%
3       Barbara   65%
3       Claire    10%

ご覧のとおり、1か月目と3ヶ月目に同じパーセントを支払いましたが、2ヶ月目にアリスに同じ25%を与えましたが、バーバラは50%を獲得し、クレアは25%を獲得しました。

私が知りたいのは、私が今までに与えたすべての明確な分布です。この場合、2つは1か月と3ヶ月、1か月目に2つあります。

結果が次のように見えると思います(注:ID、シーケンサーなど、問題ではありません)

ID      Employee  PercentOfTotal
--------------------------------
X       Alice     25%
X       Barbara   65%
X       Claire    10%

Y       Alice     25%
Y       Barbara   50%
Y       Claire    25%

簡単に思えますか?困惑しています!誰かがエレガントなソリューションを持っていますか?この質問を書いているときにこのソリューションをまとめただけです。または、私が何かを学ぶ別の方法かもしれません。

WITH temp_ids (Month)
AS
(
  SELECT DISTINCT MIN(Month)
    FROM employees_paid
  GROUP BY PercentOfTotal
)
SELECT EMP.Month, EMP.Employee, EMP.PercentOfTotal
  FROM employees_paid EMP
         JOIN temp_ids IDS ON EMP.Month = IDS.Month
GROUP BY EMP.Month, EMP.Employee, EMP.PercentOfTotal

ありがとうy'all! - リッキー

役に立ちましたか?

解決

私はパフォーマンスが大きくないと仮定しています(サブクエリの原因)

SELECT * FROM employees_paid where Month not in (
     SELECT
          a.Month
     FROM
          employees_paid a
          INNER JOIN employees_paid b ON 
               (a.employee = B.employee AND 
               a.PercentOfTotal = b.PercentOfTotal AND 
               a.Month > b.Month)
     GROUP BY
          a.Month,
          b.Month
     HAVING
          Count(*) = (SELECT COUNT(*) FROM employees_paid c 
               where c.Month = a.Month)
     )
  1. インナーセレクトは、一致する従業員とパーセンテージの組み合わせ(同じ月を除く)を識別するために自己結合を行います。 >結合は、1月1日のエントリ=月3日のエントリの場合、1つの一致セットのみが取得されることを保証します。1月1日、月3ヶ月、3か月3か月ではなく、3か月のエントリの組み合わせのみを取得します。
  2. 次に、月〜月の組み合わせの一致したエントリのカウントによってグループ化されます
  3. それから
  4. 外側の選択は、内側クエリ(フルセットの一致のあるもの)によって返されるエントリを除くすべてのエントリを取得します

他のヒント

これにより、要求されたものとはわずかに異なる形式で回答が得られます。

SELECT DISTINCT
    T1.PercentOfTotal AS Alice,
    T2.PercentOfTotal AS Barbara,
    T3.PercentOfTotal AS Claire
FROM employees_paid T1
JOIN employees_paid T2
  ON T1.Month = T2.Month AND T1.Employee = 'Alice' AND T2.Employee = 'Barbara'
JOIN employees_paid T3
  ON T2.Month = T3.Month AND T3.Employee = 'Claire'

結果:

Alice   Barbara  Claire
25%     50%      25%
25%     65%      10%

必要に応じて使用できます unpivot この結果をあなたが求めたフォームに設定するには。

SELECT rn AS ID, Employee, PercentOfTotal
FROM (
    SELECT *, ROW_NUMBER() OVER (ORDER BY Alice) AS rn
    FROM (
        SELECT DISTINCT
            T1.PercentOfTotal AS Alice,
            T2.PercentOfTotal AS Barbara,
            T3.PercentOfTotal AS Claire
        FROM employees_paid T1
        JOIN employees_paid T2 ON T1.Month = T2.Month AND T1.Employee = 'Alice'
                                                      AND T2.Employee = 'Barbara'
        JOIN employees_paid T3 ON T2.Month = T3.Month AND T3.Employee = 'Claire'
    ) T1
) p UNPIVOT (PercentOfTotal FOR Employee IN (Alice, Barbara, Claire)) AS unpvt

結果:

ID  Employee  PercentOfTotal  
1   Alice     25%
1   Barbara   50%      
1   Claire    25%             
2   Alice     25%             
2   Barbara   65%              
2   Claire    10%               

あなたが望むのは、毎月の分布が他の月に見つけたい署名またはパターンとして機能することです。明確ではないのは、価値があった従業員がパーセンテージの分解と同じくらい重要であるかどうかです。たとえば、Alice = 65%、Barbara = 25%、Claire = 10%はあなたの例の3か月目と同じですか?私の例では、私はそれが同じではないと推測しました。 Martin Smithのソリューションと同様に、各パーセンテージに10を掛けることで署名が見つかります。これは、すべてのパーセンテージ値が1未満であると仮定しています。たとえば、誰かが110%の割合を持つことができれば、このソリューションに問題が発生します。

With Employees As
    (
    Select 1 As Month, 'Alice' As Employee, .25 As PercentOfTotal
    Union All Select 1, 'Barbara', .65
    Union All Select 1, 'Claire', .10
    Union All Select 2, 'Alice', .25
    Union All Select 2, 'Barbara', .50
    Union All Select 2, 'Claire', .25
    Union All Select 3, 'Alice', .25
    Union All Select 3, 'Barbara', .65
    Union All Select 3, 'Claire', .10
    )
    , EmployeeRanks As
    (
    Select Month, Employee, PercentOfTotal
        , Row_Number() Over ( Partition By Month Order By Employee, PercentOfTotal ) As ItemRank
    From Employees
    )
    , Signatures As
    (
    Select Month
        , Sum( PercentOfTotal * Cast( Power( 10, ItemRank ) As bigint) ) As SignatureValue
    From EmployeeRanks
    Group By Month
    )
    , DistinctSignatures As
    (
    Select Min(Month) As MinMonth, SignatureValue
    From Signatures
    Group By SignatureValue
    )
Select E.Month, E.Employee, E.PercentOfTotal
From Employees As E
    Join DistinctSignatures As D
        On D.MinMonth = E.Month

私があなたを正しく理解していたなら、一般的な解決策のために、あなたはグループ全体を一緒に連結する必要があると思います - 例: Alice:0.25, Barbara:0.50, Claire:0.25. 。次に、異なるグループを選択して、次のようなことがそれを行うように(むしろ不格好に)。

WITH EmpSalaries
AS
(

SELECT 1 AS Month, 'Alice' AS Employee, 0.25 AS PercentOfTotal UNION ALL
SELECT 1 AS Month, 'Barbara' AS Employee, 0.65 UNION ALL
SELECT 1 AS Month, 'Claire' AS Employee, 0.10 UNION ALL

SELECT 2 AS Month, 'Alice' AS Employee, 0.25 UNION ALL
SELECT 2 AS Month, 'Barbara' AS Employee, 0.50 UNION ALL
SELECT 2 AS Month, 'Claire' AS Employee, 0.25 UNION ALL

SELECT 3 AS Month,  'Alice' AS Employee, 0.25 UNION ALL
SELECT 3 AS Month,  'Barbara' AS Employee, 0.65 UNION ALL
SELECT 3 AS Month,  'Claire' AS Employee, 0.10 
),
Months AS 
(
SELECT DISTINCT Month FROM EmpSalaries
),
MonthlySummary AS
(
SELECT Month,
Stuff(
            (
            Select ', ' + S1.Employee + ':' + cast(PercentOfTotal as varchar(20))
            From EmpSalaries As S1
            Where S1.Month = Months.Month
            Order By S1.Employee
            For Xml Path('')
            ), 1, 2, '') As Summary
FROM Months
)
SELECT * FROM EmpSalaries
WHERE Month IN (SELECT MIN(Month)
                FROM MonthlySummary
                GROUP BY Summary)

この質問を書いている間、私はこのソリューションをまとめました。

うまくいかないと思います。ここでは、さらに2つのグループ(それぞれ月= 4と5)を追加しましたが、これは明確であると考えますが、結果は同じ月= 1と2のみです。

WITH employees_paid (Month, Employee, PercentOfTotal)
AS 
(
 SELECT 1, 'Alice', 0.25
 UNION ALL
 SELECT 1, 'Barbara', 0.65
 UNION ALL
 SELECT 1, 'Claire', 0.1
 UNION ALL
 SELECT 2, 'Alice', 0.25
 UNION ALL
 SELECT 2, 'Barbara', 0.5
 UNION ALL
 SELECT 2, 'Claire', 0.25
 UNION ALL
 SELECT 3, 'Alice', 0.25
 UNION ALL
 SELECT 3, 'Barbara', 0.65
 UNION ALL
 SELECT 3, 'Claire', 0.1
 UNION ALL
 SELECT 4, 'Barbara', 0.25
 UNION ALL
 SELECT 4, 'Claire', 0.65
 UNION ALL
 SELECT 4, 'Alice', 0.1
 UNION ALL
 SELECT 5, 'Diana', 0.25
 UNION ALL
 SELECT 5, 'Emma', 0.65
 UNION ALL
 SELECT 5, 'Fiona', 0.1
), 
temp_ids (Month)
AS
(
 SELECT DISTINCT MIN(Month)
   FROM employees_paid
  GROUP 
     BY PercentOfTotal
)
SELECT EMP.Month, EMP.Employee, EMP.PercentOfTotal
  FROM employees_paid AS EMP
       INNER JOIN temp_ids AS IDS 
          ON EMP.Month = IDS.Month
 GROUP 
    BY EMP.Month, EMP.Employee, EMP.PercentOfTotal;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top