سؤال

وأنا أبحث عن استعلام واحد التي يمكن تحويل المعلومات التالية في الجدول

name:time    :state
a   :10:00 AM:login
b   :10:05 AM:login
a   :10:06 AM:chatting
a   :10:08 AM:Idle
b   :10:11 AM:chatting
a   :10:10 AM:Logout
b   :10:12 AM:Logout

وإلى شيء من هذا القبيل (نظرا لاتساع الوقت 10:00 حتي 10:15 كفترة الاستعلام)

name: State    :Duration
a   : chatting :2 Minutes 
a   : Idle     :2 Minutes
b   : chatting :1 Minute

ويمكن أن يتم ذلك فقط باستخدام SQL؟ أستخدمه ينفورميكس النسخة 11.5

هل كانت مفيدة؟

المحلول

ويمكن ان يتم ذلك في بيان SQL واحد. وهنا دليل على ذلك.

إعداد

CREATE TEMP TABLE eventtable
(
    name CHAR(3) NOT NULL,
    time DATETIME HOUR TO MINUTE NOT NULL,
    state CHAR(8) NOT NULL
);

INSERT INTO eventtable(name, time, state) VALUES('a', '10:00', 'login');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:05', 'login');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:06', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:08', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:10', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:12', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:01', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:02', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:03', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:04', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:05', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:06', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:07', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:08', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:09', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:12', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:13', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:14', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:15', 'Logout');

الاستعلام الصحيح

ملاحظة الظروف. الجدول نتيجة يجب أن تستبعد فترات بين "الدخول"، وأول حدث آخر. علاوة على ذلك، يجب أن تستبعد الفترة ما بين 'الخروج' والحدث التالي (يفترض أن 'تسجيل الدخول'). انضمام الذاتي بين الجدول على اسم العمود ومن ثم الانضمام إلى غير المتماثلة على الوقت العمود (باستخدام '<') يضمن أن الأحداث في ترتيب الوقت. وNOT EXISTS يضمن الفرعية حدد أن تعتبر فقط الأحداث المجاورة. باستخدام بين وفي الاستعلام الفرعي هو خطأ لأنه يتضمن نقطة نهاية، وأنه من الأهمية بمكان أن r1.time وr2.time تستثنى من النطاق؛ استغرق الأمر بضع دقائق لاكتشاف هذا الخطأ (ركض الاستعلام ولكن إرجاع أية صفوف، ولكن لماذا ؟)!

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS duration
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND NOT EXISTS (SELECT 1 FROM eventtable r3
                            WHERE r3.time > r1.time AND r3.time < r2.time
                      AND r3.name = r1.name
                      AND r3.name = r2.name);

وهذا ينتج الجواب:

name state      duration
a    chatting   0:02
a    Idle       0:02
b    chatting   0:01

c    chatting   0:01
c    Idle       0:01
c    Idle       0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01

وقيمة "مدة" هي ساعة الفاصل إلى الدقيقة؛ إذا كنت ترغب في القيمة في دقائق معدودة فقط، لديك لتحويله مع الزهر (باستخدام 4 لدقة للسماح لفترات تصل إلى 1440 دقيقة، أو 1 اليوم، البيانات غير واضحة لأطر زمنية أطول):

(r2.time - r1.time)::INTERVAL MINUTE(4) TO MINUTE

وأو:

CAST (r2.time - r1.time AS INTERVAL MINUTE(4) TO MINUTE)

وIBM ينفورميكس الديناميكي خادم (IDS) والترميزات مطول جدا عن الثوابت الوقت. في المعيار SQL، يمكنك استخدام الوقت ونوع ووقت '10: 00: 00 'كقيمة، ولكن الثواني يكون ضروريا في SQL القياسية الصارمة. IDS لا توفر أنواع الدقيق الذي يريده الناس - مثل DATETIME ساعة إلى دقيقة. كنت أيضا كتابة MINUTE INTERVAL (4) في SQL القياسية. و"إلى دقيقة" يجب أن يكون اختياريا.

الاستعلام غير صحيح

في تعليقي على الجواب راي هدايت، وأشرت إلى أن EXISTS استعلام فرعي هو ضروري لضمان أن الأحداث قيد النظر هي متجاورة - لا توجد أحداث التدخل. وهنا نفس الاستعلام مع بداية ونهاية مرات إضافة إلى الإخراج، والمشرقية بند في عداد المفقودين (و "مدة" إعادة تسمية "مرور"):

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS lapse,
       r1.time AS start, r2.time AS end
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE;

وهذا ينتج الجواب:

name state     lapse start end
a    chatting   0:04 10:06 10:10
a    chatting   0:02 10:06 10:08
a    Idle       0:02 10:08 10:10
b    chatting   0:01 10:11 10:12
c    chatting   0:13 10:02 10:15
c    chatting   0:12 10:02 10:14
c    chatting   0:11 10:02 10:13
c    chatting   0:10 10:02 10:12
c    chatting   0:09 10:02 10:11
c    chatting   0:07 10:02 10:09
c    chatting   0:06 10:02 10:08
c    chatting   0:05 10:02 10:07
c    chatting   0:04 10:02 10:06
c    chatting   0:03 10:02 10:05
c    chatting   0:02 10:02 10:04
c    chatting   0:01 10:02 10:03
c    Idle       0:12 10:03 10:15
c    Idle       0:11 10:03 10:14
c    Idle       0:10 10:03 10:13
c    Idle       0:09 10:03 10:12
c    Idle       0:08 10:03 10:11
c    Idle       0:06 10:03 10:09
c    Idle       0:05 10:03 10:08
c    Idle       0:04 10:03 10:07
c    Idle       0:03 10:03 10:06
c    Idle       0:02 10:03 10:05
c    Idle       0:01 10:03 10:04
c    Idle       0:10 10:05 10:15
c    Idle       0:09 10:05 10:14
c    Idle       0:08 10:05 10:13
c    Idle       0:07 10:05 10:12
c    Idle       0:06 10:05 10:11
c    Idle       0:04 10:05 10:09
c    Idle       0:03 10:05 10:08
c    Idle       0:02 10:05 10:07
c    Idle       0:01 10:05 10:06
c    Idle       0:08 10:07 10:15
c    Idle       0:07 10:07 10:14
c    Idle       0:06 10:07 10:13
c    Idle       0:05 10:07 10:12
c    Idle       0:04 10:07 10:11
c    Idle       0:02 10:07 10:09
c    Idle       0:01 10:07 10:08
c    chatting   0:04 10:11 10:15
c    chatting   0:03 10:11 10:14
c    chatting   0:02 10:11 10:13
c    chatting   0:01 10:11 10:12
c    Idle       0:03 10:12 10:15
c    Idle       0:02 10:12 10:14
c    Idle       0:01 10:12 10:13
c    chatting   0:02 10:13 10:15
c    chatting   0:01 10:13 10:14
c    Idle       0:01 10:14 10:15

وهذا يدل على مدى تلاءم كل صف بداية مؤهلة للمستخدم 'ج' مع نهاية كل صف مؤهل، وإعطاء العديد من الصفوف زائفة من البيانات. وNOT EXISTS استعلام فرعي هو موضوع مشترك عند التعامل مع الاستعلامات تستند إلى الوقت. يمكنك العثور على معلومات حول هذه العمليات والتي سنودجراس " تطوير تطبيقات المنحى الوقت في SQL "(PDF على شبكة الإنترنت في URL)، والتاريخ، وداروين Lorentzos" الزمني البيانات والعلائقية نموذج ".

نصائح أخرى

وأنا متأكد من أنه يمكن أن يتم ذلك باستخدام SQL فقط، انها سوف تأخذ مني قدرا كبيرا من الوقت من أجل التوصل إلى استعلام بالنسبة لك، وأنا تحريره في حين انتهيت. إن الخطوات الأساسية أعتقد أن تكون أول من حساب مقدار الوقت كل واحد يأخذ (القيام به من خلال اتخاذ كل الدخول والانضمام إليها للدخول المقبل وطرح لمعرفة الفرق الوقت) ثم مجموعة بسيطة من خلال بند مع المبلغ سيكون من السهل الحصول على ذلك في النموذج الذي وصفته.

وتحرير: هنا ما خطرت لي

SELECT l.userid, l.state, SUM(t.minutes) AS duration
FROM Log l 
INNER JOIN (
    SELECT l1.id, (l2.time - l1.time) AS minutes
    FROM Log l1, Log l2
    WHERE l2.time == ( 
        -- find the next entry --
        SELECT TOP 1 ls.time
        FROM Log ls
        WHERE ls.Time > l1.Time && ls.userid = l1.userid
        ORDER BY ls.Time
    )
) t ON l.id == t.id
GROUP BY l.userid, l.state
ORDER BY l.userid

وهذا هو الدور شبة الكود، والمصنوعة I تصل جميع أسماء الجداول والأشياء، وأنك لن تكون قادرة على مجرد طرح مرة واحدة من آخر، فسوف يكون من المحتمل أن تستخدم دالة DateDiff. وبالاضافة الى ذلك على الرغم من أنني أعتقد أن هذا هو جوهر ذلك. أعتقد SQL هي واحدة من أكثر اللغات مذهلة، يمكنك أن تفعل أي شيء تقريبا مع رمز قليلا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top