تشغيل الإجمالي حسب السجلات المجمعة في الجدول
-
22-07-2019 - |
سؤال
لدي جدول مثل هذا (Oracle، 10)
Account Bookdate Amount
1 20080101 100
1 20080102 101
2 20080102 200
1 20080103 -200
...
ما أحتاج إليه هو جدول جديد مجمع حسب ترتيب الحساب حسب تصاعدي للحساب وتاريخ الحجز تصاعدي مع حقل إجمالي قيد التشغيل، مثل هذا:
Account Bookdate Amount Running_total
1 20080101 100 100
1 20080102 101 201
1 20080103 -200 1
2 20080102 200 200
...
هل هناك طريقة بسيطة للقيام بذلك؟
شكرا لك مقدما.
المحلول
هل حقا بحاجة الى طاولة اضافية؟
ويمكنك الحصول على هذه البيانات التي تحتاج إليها مع استعلام بسيط، والتي يمكن أن تخلق من الواضح كطريقة عرض إذا كنت تريد أن تبدو وكأنها الجدول.
وهذا سوف تحصل على البيانات التي تبحث عن:
select
account, bookdate, amount,
sum(amount) over (partition by account order by bookdate) running_total
from t
/
وهذا سيخلق وجهة نظر لتظهر لك البيانات كما لو كان جدول:
create or replace view t2
as
select
account, bookdate, amount,
sum(amount) over (partition by account order by bookdate) running_total
from t
/
إذا كنت حقا بحاجة الجدول، هل يعني أنك في حاجة إليها تحديثها باستمرار؟ أو مجرد مرة واحدة؟ من الواضح ما اذا كان لمرة واحدة يمكنك فقط "إنشاء الجدول كما حدد" باستخدام الاستعلام أعلاه.
واختبار البيانات I المستخدمة هي:
create table t(account number, bookdate date, amount number);
insert into t(account, bookdate, amount) values (1, to_date('20080101', 'yyyymmdd'), 100);
insert into t(account, bookdate, amount) values (1, to_date('20080102', 'yyyymmdd'), 101);
insert into t(account, bookdate, amount) values (1, to_date('20080103', 'yyyymmdd'), -200);
insert into t(account, bookdate, amount) values (2, to_date('20080102', 'yyyymmdd'), 200);
commit;
وتحرير:
ونسيت أن أضيف؛ الذي حددته التي أردت الجدول إلى أن يؤمر - وهذا لا يجعل حقا معنى، ويجعلني أعتقد أن كنت حقا يعني أن أردت الاستعلام / عرض - طلب هو نتيجة الاستعلام تقوم بتنفيذ، لا شيء هذا inherant في الجدول (تجاهل جداول مؤشر المنظمة وما شابه ذلك).
نصائح أخرى
سأبدأ بهذا التحذير المهم جداً:لا تقم بإنشاء جدول للاحتفاظ بهذه البيانات.عندما تفعل ذلك ستجد أنك بحاجة إلى الحفاظ عليه مما سيصبح صداعًا لا ينتهي أبدًا.اكتب طريقة عرض لإرجاع العمود الإضافي إذا كنت تريد القيام بذلك.إذا كنت تعمل مع مستودع بيانات إذن ربما ستفعل شيئًا كهذا، ولكن حتى بعد ذلك تخطئ في جانب العرض إلا إذا لم تتمكن ببساطة من الحصول على الأداء الذي تحتاجه باستخدام الفهارس والأجهزة المناسبة وما إلى ذلك.
إليك استعلام سيعيد الصفوف بالطريقة التي تريدها.
SELECT
Account,
Bookdate,
Amount,
(
SELECT SUM(Amount)
FROM My_Table T2
WHERE T2.Account = T1.Account
AND T2.Bookdate <= T1.Bookdate
) AS Running_Total
FROM
My_Table T1
الحل المحتمل الآخر هو:
SELECT
T1.Account,
T1.Bookdate,
T1.Amount,
SUM(T2.Amount)
FROM
My_Table T1
LEFT OUTER JOIN My_Table T2 ON
T2.Account = T1.Account AND
T2.Bookdate <= T1.Bookdate
GROUP BY
T1.Account,
T1.Bookdate,
T1.Amount
اختبرهما من حيث الأداء واكتشف أيهما أفضل بالنسبة لك.كما أنني لم أختبرها بشكل شامل بما يتجاوز المثال الذي قدمته، لذا تأكد من اختبار بعض الحالات المتطورة.
واستخدام التحليلات، مثلما هو الحال في سؤالك الأخير:
create table accounts
( account number(10)
, bookdate date
, amount number(10)
);
delete accounts;
insert into accounts values (1,to_date('20080101','yyyymmdd'),100);
insert into accounts values (1,to_date('20080102','yyyymmdd'),101);
insert into accounts values (2,to_date('20080102','yyyymmdd'),200);
insert into accounts values (1,to_date('20080103','yyyymmdd'),-200);
commit;
select account
, bookdate
, amount
, sum(amount) over (partition by account order by bookdate asc) running_total
from accounts
order by account,bookdate asc
/
والإخراج:
ACCOUNT BOOKDATE AMOUNT RUNNING_TOTAL
---------- -------- ---------- -------------
1 01-01-08 100 100
1 02-01-08 101 201
1 03-01-08 -200 1
2 02-01-08 200 200