Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Trang 1 của 2 12 CuốiCuối
Kết quả 1 đến 10 của 15
  1. #1
    Ngày tham gia
    Sep 2015
    Bài viết
    0

    Hướng dẫn tạo mã tự động kế tiếp trên C# và SQL server (trigger)

    Hàm này dùng để tạo tự động mã kế tiếp giống như AutoCrement, nhưng AutoCrement chỉ tạo được đối với kiểu dữ liệu integer. Vậy nếu bạn muốn tạo mã kế tiếp với mã có chứa ký tự "HS0009" thì sao?

    VD: Mã học sinh cuối cùng trong bảng CSDL là HS0009, thì khi gọi hàm này nó sẽ tìm ra mã tiếp theo là HS0010, và nếu mã này là HS9999 thì mã kế tiếp sẽ là HS10000

    Để lấy mã số cuối cùng trong CSDL thì ta dùng query sắp xếp giảm dần là lấy được thoi
    VD: SELECT TOP 1 MAHS FROM HOCSINH ORDER BY MAHS DESC
    Với query trên sẽ trả về cho ta MAHS cuối cùng trong CSDL với điều kiện mã số đó phải fix width (cố định số ký tự có trong mã). Còn nếu bạn sử dụng mã không cố định số ký tự thì không dùng query trên được đâu. VD: Tôi có danh sách mã HS1,HS2,HS3,...,HS9,HS10,HS11 thì theo bạn mã tiếp theo nếu dùng query trên là gì? Nó sẽ trả về HS9 đấy! Vì mã sau khi sort thì HS9 là mã cuối cùng được trả về! Trong trường hợp này bạn phải viết 1 hàm lấy tất cả mã số, và duyệt tất cả mã số đó tách bỏ phần tiền tố "HS" đi cho vào mảng và sắp xếp giảm dần, ta lấy phần tử mảng đầu tiên đó là mã số ID cuối cùng! Với cách này thì nó sẽ tìm mã kế tiếp lâu hơn, bạn có thể viết StoreProcedure để chạy dưới CSDL thì nhanh hơn!

    Đây là hàm lấy mã cuối cùng theo query order by, với tham số truyền vào:
    + nameTable: Tên table vd ở trên là HOCSINH
    + nameSelectColumn: Tên filed muốn lấy vd MAHS
    + Trong hàm có ExecuteScalar(sql) là hàm trả về giá trị first row, first field tìm được


    Mã:
    public string GetLastID(string nameTable, string nameSelectColumn){            string sql = "SELECT TOP 1 " +nameSelectColumn +" FROM " + nameTable + " ORDER BY " + nameSelectColumn + " DESC";            return (string)ExecuteScalar(sql);}
    Và đây là hàm tìm mã kế tiếp:
    + lastID: chuỗi mã cuối cùng vừa tìm được từ hàm GetTopDataCell()
    + prefixID: Tiền tố mã. Với vd trên là "HS"


    Mã:
    public string NextID(string lastID, string prefixID)        {            if(lastID = "")           {               return prefixID+"0001";  // fixwidth default           }            int nextID = int.Parse(lastID.Remove(0, prefixID.Length)) + 1;            int lengthNumerID = lastID.Length - prefixID.Length;            string zeroNumber = "";            for (int i = 1; i <= lengthNumerID; i++)            {                if (nextID < Math.Pow(10, i))                {                    for (int j = 1; j <= lengthNumerID - i; i++)                    {                        zeroNumber += "0";                    }                    return prefixID + zeroNumber + nextID.ToString();                }            }            return prefixID + nextID;         }
    Gọi hàm:


    Mã:
    string lastID = GetLastID("HOCSINH","MAHS");string nextID = NextID(lastID,"HS");
    Đối với những dạng: KH008, KH009, KH010, KH011 như tôi nói ở trên khi sắp xếp DESC trong CSDL thì ra là: KH011, KH010, KH009, KH008 rất dễ để lấy mã cuối cùng để xử lý
    Nhưng đối với mã dạng: KH8, KH9, KH10, KH11 khi sắp xếp DESC sẽ ra: KH9, KH8, KH11, KH10 vì nó sắp xếp ưu tiên các ký tự từ bên trái sang. Vậy để tìm mã cuối cùng của mã những dạng này thì làm sao?
    - Lấy tất cả các mã trong CSDL
    - Duyệt từng mã để tách tiền tố của mã, cho vào mảng và tìm phần tử lớn nhất
    - Lấy phần tử đầu tiên của mảng và +1 để lấy mã tiếp theo
    - Lấy mã này ghép với tiền tố mã là ta lấy được mã mới
    Với cách này sẽ thực hiện chậm hơn nhiều so với mã fixwidth mà tôi nói ở trên

    Giải thuật chưa được hay, bạn nào có giải thuật tối ưu thì góp vui nhé [IMG]images/smilies/online.gif[/IMG]

    Mã:
    string sql = "SELECT MaKH FROM Customer";// Lấy DataTable từ câu truy vấn truyền vào (Apdapter Fill DataTable)DataTable tb = GetDataTable(sql);double[] arrCode = new double[tb.Rows.Count];int code;for(int i=0; i< tb.Rows.Count; i++){    code = int.Parse(b.Rows[i]["MaKH"].ToString().Remove(0,2));    arrCode[i] = code;}code = arrCode.Max() + 1;string nextID = "KH"+code;
    Phần sau: Viết trigger thêm ID có tiền tố tự động (SQL server)

  2. #2
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Để đơn giản tìm mã có tiền tố kế tiếp trên C# (vd: HS009 => HS010) mình có 1 giải pháp như sau:
    - Tạo function tìm mã kế tiếp từ mã cuối cùng như C#
    - Dùng trigger for Insert tự động dùng function tìm mã ở trên để tạo ra mã kế tiếp

    Function tìm mã kế tiếp, bạn chạy 1 lần để tạo function
    Các tham số truyền vào:
    + @lastid : mã cuối cùng trong bảng muốn tìm nextid
    + @prefix : tiền tố mã (HS0009 => HS)
    + @size: số lượng ký tự trong mã (HS0009 => 6)


    Mã:
    GOif exists (select * from sysobjects WHERE name = 'fn_NextID' AND type = 'fn')    drop function fn_NextIDGO-- @lastid là mã cuối cùng (fixwidth)-- @prefix là tiền tố mã: vd HS0001 => HS-- @size là số lượng ký tự trong mã HS0001 => 6CREATE function fn_NextID (@lastid varchar(10),@prefix varchar(10),@size int)  returns varchar(10)as    BEGIN        IF(@lastid = '')            set @lastid = @prefix + REPLICATE (0,@size - LEN(@prefix))         declare @num_nextid int, @nextid varchar(10)        set @lastid = LTRIM(RTRIM(@lastid))        -- number next id        set @num_nextid = replace(@lastid,@prefix,'') + 1        -- bo di so luong ky tu tien to        set @size = @size - len(@prefix)        -- replicate số lượng số 0 REPLICATE(0,3) => 000        set @nextid = @prefix + REPLICATE (0,@size - LEN(@prefix))         set @nextid = @prefix + RIGHT(REPLICATE(0, @size) + CONVERT (VARCHAR(MAX), @num_nextid), @size)        return @nextid    END;
    Sử dụng:


    Mã:
    select dbo.fn_NextID ('','HS',6)  -- HS0001 (mã đầu tiên)select dbo.fn_NextID ('HS0009','HS',6)  -- HS0010
    Tiếp theo ta sẽ viết trigger for insert để tự động thêm mã kế tiếp khi ta insert 1 bộ mới
    VD: tôi có bảng test (id,name) với id là mã


    Mã:
    GOif exists (select * from sysobjects WHERE name = 'tr_NextID_Test' AND type = 'TR')    drop trigger tr_NextID_TestGOcreate trigger tr_NextID_Test on testfor insertas    begin        DECLARE @lastid nvarchar(10)        SET @lastid  = (SELECT TOP 1 id from test order by id desc)        UPDATE test set id = dbo.fn_NextID (@lastid,'HS',7) where id = ''    end
    Test thử nhé:

    Mã:
    insert test (id,name) values ('','abc')select * from test
    Quét khối, mỗi lần ấn F5 sẽ cho ra mã kế tiếp như ý muốn. lưu ý tham số thứ nhất @lastid bỏ trống nhé!
    Vệc tự động thêm trong SQL có vẻ đơn giản hơn nhỉ, nhưng bù lại các bạn phải xây dựng tất cả các trigger tương ứng với các bảng thêm. Chúc sức khỏe!

  3. #3
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Bạn cho mình hỏi tí nha,
    Mình đã làm thử theo cách của bạn và kết quả chạy okie, nhưng mình có thắc mắc vài chỗ nhờ bạn giải thích giúp:
    1. Function fn_NextID được đưa vào bảng sysobjects nhưng khi mình vào System Table thì không có bảng này.
    2. Mình có thể mở lại trigger tr_NextID_Test nhưng không thể tìm thấy trigger fn_NextID.
    Vấn đề của mình ở đây là cần tìm vị trí của trigger fn_NextID.?

  4. #4
    Ngày tham gia
    Sep 2015
    Đang ở
    hà nội
    Bài viết
    0
    Những đoạn mã này rất hay, tuy nhiên bản thân nó còn có thể được nâng cấp lên một mức mới
    Đối với những chuỗi này, cần phải define những con số sử dụng ngay từ đầu, như vậy những hàm này mới có thể được tái sử dụng nhiều lần
    Vì một khi sử dụng những hàm này trong các dự án lớn thì chúng ta không bao giờ chỉ sử dụng một lần
    nên truyền các tham số vào sẽ giúp cho việc sử dụng lại nhiều lần ở những table khác một cách dễ dàng hơn

    Để nghiên cứu chút rồi có thể sẽ sửa chữa lại cho thích hợp hơn nữa.

    Bài hướng dẫn này thật sự rất hay nhưng thường mình add trigger ngay bảng mình làm luôn chứ không đưa ra một bảng khác như trên

  5. #5
    Ngày tham gia
    Feb 2014
    Bài viết
    0
    mình làm tương tự nhưng lại xuất hiện lỗi

    mong đc giúp đỡ.

    The name 'ExecuteScalar' does not exist in the current context

  6. #6
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Các bạn ơi cho mình hỏi, giả sử trong bảng có 2 mã là H09 và H10, bây giờ mình thêm thì mã sẽ là H11, nhưng giả sử trong csdl của mình ko còn H10(do bị xóa) mà chỉ có H09 thì nó có tự động thêm mã H11 không? và nếu là mã tự động tăng thì mình phải viết câu lệnh sql ntn để lấy đc mã tiếp theo khi mình insert chứ ko phải là mã lớn nhất trong csdl nha. Mình cảm ơn các bạn!

  7. #7
    Không cần phức tạp vậy đâu, cái auto này thực chất phụ thuộc vào số ID đó có bị xóa trong tương lai hay không, tức là có làm khóa chính hay không? Nếu làm khóa chính thì đâu xóa được, do đó bạn chỉ cần viết 1 cái store đơn giản là đếm tổng số mã, sau đó lấy tổng + 1 là ra 1 số mới, thay vào cái đuôi là trả ra mã mới!!! Còn nếu ko làm khóa chính bạn sẽ viết 1 cái store proc cho 1 vòng lặp kiểm tra xem nó bị đứt quãng chỗ nào thì thay thế vào, mình nghĩ mấy cái này khá đơn giản. Các bạn cứ thử xem, cái store chỉ cần vài dòng đơn gian nhưng vẫn chạy ổn định, mình vẫn thường làm như vậy trong các dự án phần mềm và chưa bao giờ chạy sai!!!!

  8. #8
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Trích dẫn Gửi bởi thien.mylove
    Không cần phức tạp vậy đâu, cái auto này thực chất phụ thuộc vào số ID đó có bị xóa trong tương lai hay không, tức là có làm khóa chính hay không? Nếu làm khóa chính thì đâu xóa được, do đó bạn chỉ cần viết 1 cái store đơn giản là đếm tổng số mã, sau đó lấy tổng + 1 là ra 1 số mới, thay vào cái đuôi là trả ra mã mới!!! Còn nếu ko làm khóa chính bạn sẽ viết 1 cái store proc cho 1 vòng lặp kiểm tra xem nó bị đứt quãng chỗ nào thì thay thế vào, mình nghĩ mấy cái này khá đơn giản. Các bạn cứ thử xem, cái store chỉ cần vài dòng đơn gian nhưng vẫn chạy ổn định, mình vẫn thường làm như vậy trong các dự án phần mềm và chưa bao giờ chạy sai!!!!
    nếu mình cần xóa 1 đối tượng thì xóa luôn khóa chính chứ bạn???
    lúc đó mình cần phải xét lại mã mình đã xóa để cấp lại khi thêm mới chứ???

  9. #9
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Mình thì làm theo cách này :
    Trước tiên tạo 1 bảng tên là ...gì thì tùy.Mình đặt là AutoID
    Mã:
    create table AutoID
    (
    	Ma int identity primary key not null,
    	Ten nvarchar(200),
    	TienTo varchar(10),
    	GiaTri int
    )
    Xem cụ thể hình bên dưới.
    Sau đó tạo 1 cái hàm sinh mã tự động.

    Mã:
    public string TaoMa(int maAutoID)
            {
                int giatri;
                try
                {
                    string sql=String.Format("select * from AutoID where Ma='{0}'", maAutoID);
                    SqlCommand cmd = new SqlCommand(sql,con); 
                    SqlDataReader read = cmd.ExecuteReader();
                    while (read.Read())
                    {
                        string tiento = read.GetValue(2).ToString();
                        giatri = (int)read.GetValue(3);
                        if (giatri==0)
                        {
                            ketqua = tiento + "00001";
                        }
                        else
                        {
                            giatri = giatri + 1;
    
                            if (giatri < 10)
                                ketqua = String.Format("{0}0000{1}", tiento, giatri);
                            else if (giatri >= 10 && giatri < 100)
                                ketqua = String.Format("{0}000{1}", tiento, giatri);
                            else if (giatri >= 100 && giatri < 1000)
                                ketqua = String.Format("{0}00{1}", tiento, giatri);
                            else if (giatri >= 1000 && giatri < 10000)
                                ketqua = String.Format("{0}0{1}", tiento, giatri);
                            else
                                ketqua = tiento + giatri;
                        }
                    }
                    read.Close();
                }
                catch
                {
                    XtraMessageBox.Show("Lỗi kết nối", "Chú ý", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                return ketqua;
            }
    Cách này vừa có thể tạo mã tự tăng và cũng vừa có thể tạo mã do người dùng nhập vào rất linh hoạt.
    Khi insert 1 bản ghi nào đó thì đồng thời ta lại update lại bảng AutoID cho trường value tăng lên 1.

  10. #10
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Rất hay bạn ah. Phải thử gấp cho nóng

 

 
Trang 1 của 2 12 CuốiCuối

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •