पंक्तियों की लगातार प्रत्येक श्रृंखला की कुल अवधि ज्ञात कीजिए


11

MySQL संस्करण

कोड MySQL 5.5 में चलेगा

पृष्ठभूमि

मेरे पास निम्नलिखित की तरह एक तालिका है

CREATE TABLE t
( id INT NOT NULL AUTO_INCREMENT
, patient_id INT NOT NULL
, bed_id INT NOT NULL
, ward_id INT NOT NULL
, admitted DATETIME NOT NULL
, discharged DATETIME
, PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

यह तालिका एक अस्पताल में रोगियों के बारे में है और यह उन बेडों को संग्रहीत करता है जहां प्रत्येक रोगी को अस्पताल में भर्ती होने के दौरान कुछ समय बिताया जाता है।

प्रत्येक वार्ड में कई बिस्तर हो सकते हैं और प्रत्येक रोगी एक ही वार्ड के भीतर एक अलग बिस्तर पर जा सकता है।

उद्देश्य

मैं जो करना चाहता हूं वह यह है कि एक विशिष्ट वार्ड में एक अलग वार्ड में स्थानांतरित किए बिना प्रत्येक रोगी ने कितना समय बिताया। यानी मैं उसी वार्ड के भीतर बिताए गए कुल समय की कुल अवधि का पता लगाना चाहता हूं।

परीक्षण का मामला

-- Let's assume that ward_id = 1 corresponds to ICU (Intensive Care Unit)
INSERT INTO t
  (patient_id, bed_id, ward_id, admitted, discharged)
VALUES

-- Patient 1 is in ICU, changes some beds, then he is moved 
-- out of ICU, back in and finally he is out.
(1, 1, 1, '2015-01-06 06:05:00', '2015-01-07 06:04:00'),
(1, 2, 1, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(1, 1, 1, '2015-01-07 07:08:00', '2015-01-08 08:11:00'),
(1, 4, 2, '2015-01-08 08:11:00', '2015-01-08 09:11:00'),
(1, 1, 1, '2015-01-08 09:11:00', '2015-01-08 10:11:00'),
(1, 3, 1, '2015-01-08 10:11:00', '2015-01-08 11:11:00'),
(1, 1, 2, '2015-01-08 11:11:00', '2015-01-08 12:11:00'),

-- Patient 2 is out of ICU, he gets inserted in ICU, 
-- changes some beds and he is back out
(2, 1, 2, '2015-01-06 06:00:00', '2015-01-07 06:04:00'),
(2, 1, 1, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(2, 3, 1, '2015-01-07 07:08:00', '2015-01-08 08:11:00'),
(2, 1, 2, '2015-01-08 08:11:00', '2015-01-08 09:11:00'),

-- Patient 3 is not inserted in ICU
(3, 1, 2, '2015-01-08 08:10:00', '2015-01-09 09:00:00'),
(3, 2, 2, '2015-01-09 09:00:00', '2015-01-10 10:01:00'),
(3, 3, 2, '2015-01-10 10:01:00', '2015-01-11 12:34:00'),
(3, 4, 2, '2015-01-11 12:34:00', NULL),

-- Patient 4 is out of ICU, he gets inserted in ICU without changing any beds
-- and goes back out.
(4, 1, 2, '2015-01-06 06:00:00', '2015-01-07 06:04:00'),
(4, 2, 1, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(4, 1, 2, '2015-01-07 07:08:00', '2015-01-08 09:11:00'),

-- Patient 5 is out of ICU, he gets inserted in ICU without changing any beds
-- and he gets dismissed.
(5, 1, 2, '2015-01-06 06:00:00', '2015-01-07 06:04:00'),
(5, 3, 2, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(5, 1, 1, '2015-01-07 07:08:00', '2015-01-08 09:11:00'),

-- Patient 6 is inserted in ICU and he is still there
(6, 1, 1, '2015-01-11 12:34:00', NULL);

वास्तविक तालिका में पंक्तियाँ लगातार नहीं होती हैं, लेकिन प्रत्येक रोगी के लिए एक पंक्ति == अगली पंक्ति के प्रवेश टाइमस्टैम्प से छुट्टी टाइमस्टैम्प होती है।

SQLFiddle

http://sqlfiddle.com/#!2/b5fe5

अपेक्षित परिणाम

मैं निम्नलिखित की तरह कुछ लिखना चाहूंगा:

SELECT pid, ward_id, admitted, discharged
FROM  (....)
WHERE ward_id = 1;

(1, 1, '2015-01-06 06:05:00', '2015-01-08 08:11:00'),
(1, 1, '2015-01-08 09:11:00', '2015-01-09 11:11:00'),
(2, 1, '2015-01-07 06:04:00', '2015-01-08 08:11:00'),
(4, 1, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(5, 1, '2015-01-07 07:08:00', '2015-01-08 09:11:00'),
(6, 1, '2015-01-11 12:34:00', NULL);

कृपया, ध्यान दें कि हम patient_id द्वारा समूह नहीं कर सकते हैं। हमें प्रत्येक ICU यात्रा के लिए एक अलग रिकॉर्ड प्राप्त करना होगा।

इसे और अधिक स्पष्ट रूप से कहने के लिए, यदि कोई मरीज आईसीयू में समय बिताता है, तो इससे बाहर निकलता है और फिर वापस लौटता है, मुझे प्रत्येक आईसीयू यात्रा में खर्च किए गए कुल समय को पुनः प्राप्त करने की आवश्यकता है (अर्थात दो रिकॉर्ड)


1
एक वाक्पटु प्रश्न के लिए +1, एक जटिल (और दिलचस्प) समस्या को स्पष्ट रूप से समझाता है। अगर मैं इसे SQLFiddle के अतिरिक्त बोनस के लिए दो बार वोट कर सकता हूं, तो मैं करूंगा। हालाँकि, मेरी वृत्ति यह है कि CTE (सामान्य टेबल एक्सप्रेशन) या विंडोिंग फंक्शन्स के बिना, MySQL में यह संभव नहीं होगा। आप किस देव वातावरण का उपयोग कर रहे हैं, यानी आप कोड के माध्यम से ऐसा करने के लिए बाध्य हो सकते हैं।
Vérace

@ Vérace I को कोड लिखने के लिए कहा गया है जो ICU बेड के अनुरूप सभी पंक्तियों को पुनः प्राप्त करता है और मैं उन्हें Pyon में समूहीकृत कर रहा हूं।
pmav99

बेशक अगर यह एसक्यूएल में अपेक्षाकृत साफ तरीके से किया जा सकता है तो मैं इसे पसंद करूंगा।
pmav99

भाषाओं के रूप में, पायथन बहुत साफ है! :-) यदि आप MySQL के लिए अटके नहीं हैं और आपको F / LOSS डेटाबेस की आवश्यकता है, तो क्या मैं PostgreSQL (कई मायनों में MySQL IMHO से बेहतर) की सिफारिश कर सकता हूँ जिसमें CTE और Windowing फ़ंक्शन हैं।
वेअर

जवाबों:


4

क्वेरी 1, SQLFiddle-1 में परीक्षण किया गया

SET @ward_id_to_check = 1 ;

SELECT
    st.patient_id,
    st.bed_id AS starting_bed_id,          -- the first bed a patient uses
                                           -- can be omitted
    st.admitted,
    MIN(en.discharged) AS discharged
FROM
  ( SELECT patient_id, bed_id, admitted, discharged
    FROM t 
    WHERE t.ward_id = @ward_id_to_check
      AND NOT EXISTS
          ( SELECT * 
            FROM t AS prev 
            WHERE prev.ward_id = @ward_id_to_check
              AND prev.patient_id = t.patient_id
              AND prev.discharged = t.admitted
          )
  ) AS st
JOIN
  ( SELECT patient_id, admitted, discharged
    FROM t 
    WHERE t.ward_id = @ward_id_to_check
      AND NOT EXISTS
          ( SELECT * 
            FROM t AS next 
            WHERE next.ward_id = @ward_id_to_check
              AND next.patient_id = t.patient_id
              AND next.admitted = t.discharged
          )
  ) AS en
    ON  st.patient_id = en.patient_id
    AND st.admitted <= en.admitted
GROUP BY
    st.patient_id,
    st.admitted ;

क्वेरी 2, जो 1 के समान है लेकिन व्युत्पन्न तालिकाओं के बिना है। यह उचित अनुक्रमणिका के साथ बेहतर निष्पादन योजना होगी। SQLFiddle-2 में परीक्षण :

SET @ward_id_to_check = 1 ;

SELECT
    st.patient_id,
    st.bed_id AS starting_bed_id,
    st.admitted,
    MIN(en.discharged) AS discharged
FROM
    t AS st    -- starting period
  JOIN
    t AS en    -- ending period
      ON  en.ward_id = @ward_id_to_check
      AND st.patient_id = en.patient_id
      AND NOT EXISTS
          ( SELECT * 
            FROM t AS next 
            WHERE next.ward_id = @ward_id_to_check
              AND next.patient_id = en.patient_id
              AND next.admitted = en.discharged
          )
      AND st.admitted <= en.admitted
WHERE 
      st.ward_id = @ward_id_to_check
  AND NOT EXISTS
      ( SELECT * 
        FROM t AS prev 
        WHERE prev.ward_id = @ward_id_to_check
          AND prev.patient_id = st.patient_id
          AND prev.discharged = st.admitted
      )
GROUP BY
    st.patient_id,
    st.admitted ;

दोनों प्रश्न यह मानते हैं कि एक अद्वितीय बाधा है (patient_id, admitted)। यदि सर्वर सख्त एएनएसआई सेटिंग्स के साथ चलता है, bed_idतो GROUP BYसूची में जोड़ा जाना चाहिए ।


ध्यान दें कि मैंने सम्मिलित मानों को
फ़िडल

2
विस्मय में - मैंने वास्तव में सोचा था कि सीटीई की कमी को देखते हुए यह असंभव था। अजीब बात है, SQLFiddle में मेरे लिए पहली क्वेरी नहीं चलेगी - एक गड़बड़? दूसरे ने हालांकि, लेकिन क्या मैं सुझाव दे सकता हूं कि st.bed_id को हटा दिया जाना चाहिए, क्योंकि यह भ्रामक है। रोगी 1 ने वार्ड 1 में अपने पहले प्रवास के सभी खर्च एक ही बिस्तर में नहीं किए।
वेअर

@ Vérace, thnx सबसे पहले, मैंने सोचा, भी, कि हमें एक पुनरावर्ती CTE की आवश्यकता थी। मैंने patient_id पर एक गुम ज्वाइन ठीक कर लिया है (जो किसी ने ध्यान नहीं दिया;) और बिस्तर के बारे में अपनी बात जोड़ी।
ypercube y

@ypercube आपके उत्तर के लिए बहुत बहुत धन्यवाद! यह वास्तव में मददगार है। मैं इस पर विस्तार से अध्ययन करने जा रहा हूं :)
pmav99

0

आगे बढ़ें

SELECT patient_id,SEC_TO_TIME(SUM(elapsed_time)) elapsed
FROM (SELECT * FROM (SELECT patient_id,
UNIX_TIMESTAMP(IFNULL(discharged,NOW())) -
UNIX_TIMESTAMP(admitted) elapsed_time
FROM t WHERE ward_id = 1) AA) A
GROUP BY patient_id;

मैंने आपको अपने लैपटॉप पर स्थानीय डेटाबेस में डेटा का नमूना दिया। फिर, मैंने क्वेरी चलाई

प्रोपेस्ड क्वर्टी एक्सक्लूसिव

mysql> SELECT patient_id,SEC_TO_TIME(SUM(elapsed_time)) elapsed
    -> FROM (SELECT * FROM (SELECT patient_id,
    -> UNIX_TIMESTAMP(IFNULL(discharged,NOW())) -
    -> UNIX_TIMESTAMP(admitted) elapsed_time
    -> FROM t WHERE ward_id = 1) AA) A
    -> GROUP BY patient_id;
+------------+-----------+
| patient_id | elapsed   |
+------------+-----------+
|          1 | 76:06:00  |
|          2 | 26:07:00  |
|          4 | 01:04:00  |
|          5 | 26:03:00  |
|          6 | 118:55:48 |
+------------+-----------+
5 rows in set (0.00 sec)

mysql>

प्रोपोस्ड क्वैरी समाप्त हो गई

उपकुंजी एए में, मैं UNIX_TIMESTAMP(discharged)FROM को घटाकर UNIX_TIMESTAMP () का उपयोग करके निकले सेकंड की संख्या की गणना करता हूं UNIX_TIMESTAMP(admitted)। यदि रोगी अभी भी बिस्तर पर है (जैसा कि डिस्चार्ज होने से संकेत मिलता है NULL), मैं वर्तमान समय अब () असाइन करता हूं । फिर, मैं घटाव करता हूं। यह आपको वार्ड में अभी भी किसी भी मरीज के लिए एक अप-टू-मिनट की अवधि देगा।

फिर, मैं सेकंड के योग को पूर्ण करता हूं patient_id। अंत में, मैं प्रत्येक रोगी के लिए सेकंड लेता हूं और रोगी के रहने के घंटे, मिनट और सेकंड प्रदर्शित करने के लिए SEC_TO_TIME () का उपयोग करता हूं

कोशिश तो करो !!!


रिकॉर्ड के लिए, मैंने अपने विंडोज 7 लैपटॉप पर MySQL 5.6.22 में इसे चलाया। यह SQL Fiddle में एक त्रुटि देता है।
रोलैंडमाइसीडीडीबीए

1
उत्तर देने के लिए आपका धन्यवाद। मुझे डर है कि हालांकि यह मेरे सवाल का जवाब नहीं देता है; शायद मैं अपने विवरण में पर्याप्त स्पष्ट नहीं था। जो मैं प्राप्त करना चाहता हूं वह आईसीयू में प्रत्येक प्रवास पर बिताया गया कुल समय है। मैं रोगी द्वारा समूह नहीं करना चाहता। यदि कोई मरीज आईसीयू में समय बिताता है, तो इससे बाहर निकलता है और फिर वापस लौटता है, मुझे प्रत्येक यात्रा (यानी दो रिकॉर्ड) में बिताए गए कुल समय को पुनः प्राप्त करने की आवश्यकता है।
pmav99

एक अलग विषय पर, आपके (मूल) उत्तर पर wrt मुझे लगता है कि दो उपश्रेणियों का उपयोग करना वास्तव में आवश्यक नहीं है (यानी तालिका Aऔर AA)। मुझे लगता है कि उनमें से एक पर्याप्त है।
pmav99
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.