سؤال
وأنا أبحث عن استعلام واحد التي يمكن تحويل المعلومات التالية في الجدول
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 هي واحدة من أكثر اللغات مذهلة، يمكنك أن تفعل أي شيء تقريبا مع رمز قليلا.