7

date_trans、time_trans、price の列を含むテーブルがあります。選択クエリの後、価格列の連続した等しい値として計算される新しい列「カウント」を追加したいと思います。連続した等しい価格を持つ前の行は最終結果から削除されます。予想される出力を参照してください。

date_trans  time_trans  price   **Count**    
2011-02-22  09:39:59    58.02   1
2011-02-22  09:40:03    58.1    *ROW WILL BE REMOVED
2011-02-22  09:40:07    58.1    *ROW WILL BE REMOVED
2011-02-22  09:40:08    58.1    3
2011-02-22  09:40:10    58.15   1
2011-02-22  09:40:10    58.1    *ROW WILL BE REMOVED
2011-02-22  09:40:14    58.1    2
2011-02-22  09:40:24    58.15   1
2011-02-22  09:40:24    58.18   *ROW WILL BE REMOVED
2011-02-22  09:40:24    58.18   *ROW WILL BE REMOVED
2011-02-22  09:40:24    58.18   3
2011-02-22  09:40:24    58.15   1

テーブルから選択する SQL クエリまたは LINQ 式を提案してください

現在、選択クエリで選択したすべての行をループすることができますが、何百万もの行を選択すると数時間かかります。

私の現在のコード:

    string query = @"SELECT date_trans, time_trans,  price
                            FROM tbl_data 
                         WHERE date_trans BETWEEN '2011-02-22' AND '2011-10-21'
                        AND time_trans BETWEEN '09:30:00' AND '16:00:00'";

            DataTable dt = oUtil.GetDataTable(query);

            DataColumn col = new DataColumn("Count", typeof(int));
            dt.Columns.Add(col);

            int priceCount = 1;
            for (int count = 0; count < dt.Rows.Count; count++)
            {
                double price = Convert.ToDouble(dt.Rows[count]["price"]);
                double priceNext = (count == dt.Rows.Count - 1) ? 0 : Convert.ToDouble(dt.Rows[count + 1]["price"]);
                if (price == priceNext)
                {
                    priceCount++;
                    dt.Rows.RemoveAt(count);
                    count--;
                }
                else
                {
                    dt.Rows[count]["Count"] = priceCount;
                    priceCount = 1;
                }
            }
4

1 に答える 1

2

それは興味深いものです。必要なものは次のようなものだと思います:

SELECT MAX(date_trans), MAX(time_trans), MAX(price), COUNT(*)
FROM
    (SELECT *, ROW_NUMBER() OVER(PARTITION BY price ORDER BY date_trans, time_trans) - ROW_NUMBER() OVER(ORDER BY date_trans, time_trans) AS grp
    FROM transactions) grps
GROUP BY grp

ここで解決策を見つけました: http://www.sqlmag.com/article/sql-server/solution-to-the-t-sql-puzzle-grouping-consecutive-rows-with-a-common-element

アップデート

グループ化列には「価格」も含める必要があります。そうしないと、グループが一意にならない可能性があります。もう 1 つのことは、日付と時刻の列を結合して datetime 列にする必要があるため、ある日の終わり近くに始まり、次の日の初めに終わるグループで最大の日時値が正しくなります。これが修正されたクエリです。

SELECT MAX(CAST(date_trans AS DATETIME) + CAST(time_trans AS DATETIME)) , MAX(price), COUNT(*)
FROM
    (SELECT *, 
        CAST(ROW_NUMBER() OVER(PARTITION BY price ORDER BY date_trans, time_trans) - ROW_NUMBER() OVER(ORDER BY date_trans, time_trans) AS NVARCHAR(255)) + '-' + CAST(price AS NVARCHAR(255)) AS grp
    FROM transactions
    ORDER BY date_trans, time_trans) grps
GROUP BY grp

nvarchar ではなくバイト配列または bigint として「grp」列を使用すると、クエリがより最適になる場合があります。また、おそらくグループ内で合計したい「ボリューム」列についても言及しました。

于 2012-07-22T20:38:22.967 に答える