Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Menggabungkan kondisi dari dua kolom mysql

Ini berusaha untuk menjaga agar solusi mudah dipelihara tanpa menyelesaikan kueri terakhir semua dalam satu kesempatan yang hampir dua kali lipat ukurannya (dalam pikiran saya). Ini karena hasil harus cocok dan diwakili pada satu baris dengan acara Masuk dan Keluar yang cocok. Jadi pada akhirnya, saya menggunakan beberapa meja kerja. Ini diimplementasikan dalam prosedur tersimpan.

Prosedur tersimpan menggunakan beberapa variabel yang dibawa dengan cross join . Pikirkan cross join hanya sebagai mekanisme untuk menginisialisasi variabel. Variabel dipertahankan dengan aman, jadi saya percaya, dalam semangat dokumen sering dirujuk dalam kueri variabel. Bagian penting dari referensi adalah penanganan variabel yang aman pada garis yang memaksanya disetel sebelum kolom lain menggunakannya. Ini dicapai melalui greatest() dan least() fungsi yang memiliki prioritas lebih tinggi daripada variabel yang disetel tanpa menggunakan fungsi tersebut. Perhatikan juga bahwa coalesce() sering digunakan untuk tujuan yang sama. Jika penggunaannya tampak aneh, seperti mengambil bilangan terbesar yang diketahui lebih besar dari 0, atau 0, itu disengaja. Sengaja dalam memaksakan urutan prioritas variabel yang sedang ditetapkan.

Kolom dalam kueri menamai hal-hal seperti dummy2 etc adalah kolom yang outputnya tidak digunakan, tetapi digunakan untuk mengatur variabel di dalam, katakanlah, greatest() atau yang lain. Ini telah disebutkan di atas. Output seperti 7777 adalah pengganti di slot ke-3, karena beberapa nilai diperlukan untuk if() yang digunakan. Jadi abaikan semua itu.

Saya telah menyertakan beberapa cuplikan layar kode saat kode itu berkembang selapis demi selapis untuk membantu Anda memvisualisasikan hasilnya. Dan bagaimana iterasi pengembangan ini perlahan-lahan dilipat ke fase berikutnya untuk memperluas sebelumnya.

Saya yakin rekan-rekan saya dapat memperbaiki ini dalam satu permintaan. Aku bisa menyelesaikannya dengan cara itu. Tapi saya yakin itu akan menghasilkan kekacauan membingungkan yang akan pecah jika disentuh.

Skema:

create table attendance2(Id int, DateTime datetime, Door char(20), Active_door char(20));
INSERT INTO attendance2 VALUES
(    1,   '2016-01-01 08:00:00',  'In', ''),
(    2,   '2016-01-01 09:00:00',  'Out', ''),
(    3,   '2016-01-01 09:15:00',  'In', ''),
(    4,   '2016-01-01 09:30:00',  'In', ''),
(    5,   '2016-01-01 09:35:00',  '', 'On'),
(    6,   '2016-01-01 10:00:00',  'Out', ''),
(    7,   '2016-01-01 16:00:00',  '', 'Off');

drop table if exists oneLinersDetail;
create table oneLinersDetail
(   -- architect this depending on multi-user concurrency
    id int not null,
    dt datetime not null,
    door int not null,
    grpIn int not null,
    grpInSeq int not null,
    grpOut int not null,
    grpOutSeq int not null
);

drop table if exists oneLinersSummary;
create table oneLinersSummary
(   -- architect this depending on multi-user concurrency
    id int not null,
    grpInSeq int null,
    grpOutSeq int null,
    checkIn datetime null, -- we are hoping in the end it is not null
    checkOut datetime null -- ditto
);

Prosedur Tersimpan:

DROP PROCEDURE IF EXISTS fetchOneLiners;
DELIMITER $$
CREATE PROCEDURE fetchOneLiners()
BEGIN
    truncate table oneLinersDetail; -- architect this depending on multi-user concurrency

    insert oneLinersDetail(id,dt,door,grpIn,grpInSeq,grpOut,grpOutSeq)
    select id,dt,door,grpIn,grpInSeq,grpOut,grpOutSeq  
    from 
    (   select id,dt,door, 
        if(@lastEvt!=door and door=1, 
            greatest(@grpIn:[email protected]+1,0), 
            7777) as dummy2, -- this output column we don't care about (we care about the variable being set)
        if(@lastEvt!=door and door=2, 
            greatest(@grpOut:[email protected]+1,0), 
            7777) as dummy3, -- this output column we don't care about (we care about the variable being set)
        if (@lastEvt!=door,greatest(@flip:=1,0),least(@flip:=0,1)) as flip, 
        if (door=1 and @flip=1,least(@grpOutSeq:=0,1),7777) as dummy4, 
        if (door=1 and @flip=1,greatest(@grpInSeq:=1,0),7777) as dummy5, 
        if (door=1 and @flip!=1,greatest(@grpInSeq:[email protected]nSeq+1,0),7777) as dummy6, 
        if (door=2 and @flip=1,least(@grpInSeq:=0,1),7777) as dummy7, 
        if (door=2 and @flip=1,greatest(@grpOutSeq:=1,0),7777) as dummy8, 
        if (door=2 and @flip!=1,greatest(@grpOutSeq:[email protected]+1,0),7777) as dummy9, 
        @grpIn as grpIn, 
        @grpInSeq as grpInSeq, 
        @grpOut as grpOut, 
        @grpOutSeq as grpOutSeq, 
        @lastEvt:=door as lastEvt 
        from 
        (   select id,`datetime` as dt, 
            CASE   
                WHEN Door='in' or Active_door='on' THEN 1 
                ELSE 2 
            END as door 
            from attendance2 
            order by id 
        ) xD1 -- derived table #1
        cross join (select @grpIn:=0,@grpInSeq:=0,@grpOut:=0,@grpOutSeq:=0,@lastEvt:=-1,@flip:=0) xParams 
        order by id 
    ) xD2 -- derived table #2
    order by id;
    -- select * from oneLinersDetail;

    truncate table oneLinersSummary;    -- architect this depending on multi-user concurrency

    insert oneLinersSummary (id,grpInSeq,grpOutSeq,checkIn,checkOut)
    select distinct grpIn,null,null,null,null
    from oneLinersDetail
    order by grpIn;

    -- select * from oneLinersSummary;

    update oneLinersSummary ols
    join
    (   select grpIn,max(grpInSeq) m
        from oneLinersDetail
        where door=1
        group by grpIn
    ) d1
    on d1.grpIn=ols.id
    set ols.grpInSeq=d1.m;

    -- select * from oneLinersSummary;

    update oneLinersSummary ols
    join
    (   select grpOut,max(grpOutSeq) m
        from oneLinersDetail
        where door=2
        group by grpOut
    ) d1
    on d1.grpOut=ols.id
    set ols.grpOutSeq=d1.m;

    -- select * from oneLinersSummary;

    update oneLinersSummary ols
    join oneLinersDetail old
    on old.door=1 and old.grpIn=ols.id and old.grpInSeq=ols.grpInSeq
    set ols.checkIn=old.dt;

    -- select * from oneLinersSummary;

    update oneLinersSummary ols
    join oneLinersDetail old
    on old.door=2 and old.grpOut=ols.id and old.grpOutSeq=ols.grpOutSeq
    set ols.checkOut=old.dt;

    -- select * from oneLinersSummary;

    -- dump out the results
    select id,checkIn,checkOut
    from oneLinersSummary
    order by id;
    -- rows are left in those two tables (oneLinersDetail,oneLinersSummary)
END$$
DELIMITER ;

Uji:

call fetchOneLiners();
+----+---------------------+---------------------+
| id | checkIn             | checkOut            |
+----+---------------------+---------------------+
|  1 | 2016-01-01 08:00:00 | 2016-01-01 09:00:00 |
|  2 | 2016-01-01 09:35:00 | 2016-01-01 16:00:00 |
+----+---------------------+---------------------+

Inilah akhir dari Jawabannya. Di bawah ini adalah visualisasi pengembang tentang langkah-langkah yang mengarah pada penyelesaian prosedur tersimpan.

Versi pengembangan yang mengarah hingga akhir. Semoga ini membantu dalam visualisasi daripada hanya menjatuhkan potongan kode yang membingungkan berukuran sedang.

Langkah A

Langkah B

Keluaran Langkah B

Langkah C

Keluaran Langkah C




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Perbarui satu tabel MySQL dengan nilai dari yang lain

  2. Bagaimana meningkatkan INSERT INTO ... SELECT mengunci perilaku

  3. Sisipkan/perbarui fungsi pembantu menggunakan PDO

  4. MAKETIME() Contoh – MySQL

  5. MySQL:Aktifkan LOAD DATA LOCAL INFILE