2016-03-22 16 views
1

Sık sık yayınlamıyorum, ama bir süredir kafamı duvara çarpıyordum ve uzmanlara ulaşacağımı düşündüm. Bu projeye danışmanlık verildiği için verildiğini lütfen unutmayın.Tek Bir Sütunda 12 Ay Ödeme Durumunu Kaydetme Yolu

Aylık ödeme durumları olan bir tablom var. Tüm 12 durumdan yola çıkarak eylemler oluşturmam gerekiyor, yani ilk kayıt “Tam Ücretli” eylemi alırken, ikincisi “Ocak ödemek gerekiyor” ve üçüncüsü “Hesap Bekletme” alacaktır.

DECLARE @Payments TABLE (January NVARCHAR(20), February NVARCHAR(20), March NVARCHAR(20), April NVARCHAR(20), May NVARCHAR(20), June NVARCHAR(20), 
July NVARCHAR(20), August NVARCHAR(20), September NVARCHAR(20), October NVARCHAR(20), November NVARCHAR(20), December NVARCHAR(20)) 

INSERT @Payments VALUES 
('Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid'), 
('Unpaid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid'), 
('Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Account Hold') 

Bunu işlemek için bir öneriniz var mı? Geldiğim en iyi şey, tüm ödeme durumlarını içeren tek bir sütundur, bu yüzden en azından tek bir alana atıfta bulunabilirim (yani 111111111111 "Tam Ücretli," 211111111111 "," Ocak Ayını Ödemeli "anlamına gelir) vs.) Bana yardım edeceğinden emin değilim, ama tüm permütasyonları elle hesaplamaktan daha iyi bir şeye ihtiyacım var.Herhangi bir yardım, takdire değer.

+1

Sen int 12 bit kullanarak yapabileceğini, ancak bir tasarım olması gibi geliyor (db) bundan önce. Bence daha fazla değer/durum için 1 sütun kullanmak nadiren iyi olur. – cantSleepNow

+0

En az 12 ayrı satır kullanmalısınız, Müşteri_Number, Pay_Year, Pay_Month gibi bir şey isteyebilirsiniz. Bu daha iyi olacak ve birden çok yıl boyunca takip edilecek. – Chuck

+0

Ben bir kez aynı sorun vardı ve aynı zamanda öneri (12 bit) ile gitti ile uğraşmak çok hantal. Bu özellikle, standart T-SQL'in ikili'nin int'ye (ve tekrar tekrar) dönüştürülmesini desteklememesi gerçeğinden kaynaklanmaktadır. Kendi dönüştürücünüzü programlamanız gerekecek: http://stackoverflow.com/questions/127116/sql-server-convert-integer-to-binary-string Yani, UNPIVOT ile gidip iki sütunda saklamak istiyorum. : Ay, Durum. – Ralph

cevap

0

Bunun ne istediğini bilmiyorum. (benim açıklamada açıklandığı gibi) bu konuda gidiş öneririm göstermek için

select * 
    from (
      select * 
      from @Payments as p unpivot 
(cStatus for cMonth in (January, February, March, April, May, June, July, 
         August, September, October, November, December)) as u 
      ) as t 
    where t.cStatus <> 'Paid' 

Güncelleme:.

Yorumunuza (ID'ler hakkında) göre, ihtiyaçlarınızı daha iyi karşılayabilecek biraz geliştirilmiş bir çözüm. İlk biraz adapte kurulum: Artık

declare @Payments table 
    (
    cYear int, 
    January nvarchar(20), 
    February nvarchar(20), 
    March nvarchar(20), 
    April nvarchar(20), 
    May nvarchar(20), 
    June nvarchar(20), 
    July nvarchar(20), 
    August nvarchar(20), 
    September nvarchar(20), 
    October nvarchar(20), 
    November nvarchar(20), 
    December nvarchar(20) 
    ) 

insert @Payments 
values (2016, 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 
     'Paid', 'Paid', 'Paid', 'Paid'), 
     (2015, 'Unpaid', 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 
     'Paid', 'Paid', 'Paid', 'Paid', 'Paid'), 
     (2014, 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 'Paid', 
     'Paid', 'Paid', 'Paid', 'Account Hold') 

declare @result table 
    (
    cPeriod int primary key 
       not null, 
    cStatus nvarchar(20) 
    ) 

, iki sütuna (UNPIVOT) verileri çevirmek ve ayrı bir tabloya sonucu ekleyin: Ben bir yıl eklemek seçti,

insert into @result 
     select u.cYear * 100 + case u.cMonth 
            when N'January' then 1 
            when N'February' then 2 
            when N'March' then 3 
            when N'April' then 4 
            when N'May' then 5 
            when N'June' then 6 
            when N'July' then 7 
            when N'August' then 8 
            when N'September' then 9 
            when N'October' then 10 
            when N'November' then 11 
            when N'December' then 12 
            else 0 
           end, 
       u.cStatus 
     from @Payments as p unpivot 
(cStatus for cMonth in (January, February, March, April, May, June, July, 
         August, September, October, November, December)) as u 

Not ilk veri kümesi. Yine de, herhangi bir sayı başka biriyle kullanılabilir ve entegre edilebilir. Benim "kimliğim" şimdi YYYYMM'den oluşmaktadır. Ancak IDidIDidMM veya seçtiğiniz herhangi bir format da olabilir. Bunun gibi, iki sütuna (orijinal isteğinize çok yakın olan sadece bir sütuna) sahip olabilirsiniz. Bu verinin işlenmesi şimdi oldukça kolay ve doğrudan doğruya. Duruma Göre

Örnek: Ay

select * 
from @result as r 
where r.cPeriod/100 = 2015 -- Year 2015 

Örnek: Yıl

select * 
from @result as r 
where r.cStatus <> N'Paid' 
     or r.cStatus is null 
union all 
select * 
from @result as r 
where r.cStatus = N'Paid' 

Örnek

ben çünkü eğer bit temelinde mantığı kullanmayın tavsiye
select * 
from @result as r 
where r.cPeriod % 100 = 2 -- Februrary 
+0

Ah, bu bana veriyi yönetilebilir bir formatta verdiği için oldukça iyi. Tek sorun, her ödeme durumunun sahip olduğu benzersiz kimliğe katılacaktı. Örnek sorguya kimliğimi dahil etmedim çünkü gerekli olduğunu düşünmedim, ancak kimliğinizi unpivot'unuza eklediyseniz, yalnızca kimliğe sahip yeni bir satır bırakmış olursunuz. – user1454772

+0

@Ralph, yıl –

0

Gelecekte daha fazla durumunuz varsa, başınız dertte olacak. Ancak bu şekilde veri saklamak bazı dezavantajlara sahiptir, Onlardan saklanan verileri kolaylıkla sorgulayamazsınız.

Eğer hala bunu yapmak istiyorsanız, bir varchar alanı kullanmanızı ve her durumu (AAAAAAA, ABAAAAA, CAABAAAA) gibi bir alfabe karakteri olarak saklamanızı öneririm.

0

Belki de eyleminizi belirlemek için bir durum bildirimi kullanabilirsiniz.Sadece bir kroki değil çalışma deyimi:

select 
    [action] = case 
     --check if on hold 
     when January = 'Account Hold' or February = 'Account Hold' --or ... 
      then 'Account Hold' 
     --check for first unpaid month 
     when January = 'Unpaid' 
      then 'Need to pay January' 
     when February = 'Unpaid' 
      then 'Need to pay February' 
     --repeat for all months 
     else 'Fully Paid' 
    end 
1

Onun tüm gereksinimleri bilmeden söylemek, ama o tablo tasarımını @Payments ile sıkışmış eğer, ben Pivot seçeneği gibi zor:

DECLARE @Payments TABLE (Id int primary key, January NVARCHAR(20), February NVARCHAR(20), March NVARCHAR(20), April NVARCHAR(20), May NVARCHAR(20), June NVARCHAR(20), 
July NVARCHAR(20), August NVARCHAR(20), September NVARCHAR(20), October NVARCHAR(20), November NVARCHAR(20), December NVARCHAR(20)) 

INSERT @Payments VALUES 
(1, 'Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid'), 
(2, 'Unpaid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid'), 
(3, 'Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Paid','Account Hold') 

select Id, PaymentStatus, PaymentMonth 
from @Payments p 
unpivot ( PaymentStatus 
      for PaymentMonth in (January, February, March, April, May, June, July, August, September, October, November, December) 
     ) d 
where PaymentStatus <> 'Paid' 

İade:

Id PaymentStatus PaymentMonth 
-- ------------- ------------ 
2 Unpaid   January 
3 Account Hold December 




Bayrak maskesi eğlencelidir, ancak ihtiyaçlarınıza göre ölçeklenmeyeceğine ve tek sütunun çok fazla satın almadığına ikna olmadım. Ben size bir pislik :)

declare @months table (i int, name varchar(10)) 
insert into @months 
    select i, datename(month, dateadd(month, i, 0) - 1) 
    from ( select 1 union all select 2 union all select 3 union all select 4 union all 
       select 5 union all select 6 union all select 7 union all select 8 union all 
       select 9 union all select 10 union all select 11 union all select 12)d(i) 

declare @PaymentStatus table (Id int primary key, Mask varchar(12)); 
insert into @PaymentStatus 
    select 1, '100020000001' union all 
    select 2, '000000000001' 

select Id, [PaymentStatus] = case Flag when 1 then 'Unpaid' when 2 then 'On Hold' end, PaymentMonth 
    from @PaymentStatus 
    cross 
    apply  
      ( select m.Ordinal, m.Flag, c.PaymentMonth 
       from ( select i, substring(mask, i, 1) 
          from @months 
         ) m (Ordinal, Flag) 
       join ( select i, name 
          from @months m 
         ) c (Ordinal, PaymentMonth) on 
         m.Ordinal = c.Ordinal 
      ) d 
    where Flag <> 0; --paid 

İade olduğunu düşünür sonra gelen geliştirici garanti:

Id PaymentStatus PaymentMonth 
-- ------------- ------------ 
1 Unpaid   January 
1 On Hold   May 
1 Unpaid   December 
2 Unpaid   December 
+0

'dan bahsetmek için iyi bir nokta olmasına rağmen, çözümünüz çok fazla tabloya sahip basit aklım için biraz karmaşıktır. Ben bunu çok seviyorum. Açık ve düz ileri ve tipik bir OLTP çözümü. Benim çözümüm daha çok OLAP çözümü. Neyse, 'user1454772' şimdi seçebileceğiniz iki iyi çözüm var. Başım ağrıyor. – Ralph

+0

@Ralph ah, OP için sizi yanlış anladım. Maske örneği eğlenceli ama tam olarak kullanışlı değil. –

İlgili konular