Tìm Kiếm Với Nhiều Tham Số

Vũ Huy Tâm

Khi ta cần viết một thủ tục để tìm kiếm dữ liệu dựa vào các tham số đầu vào, ta có thể hình dung ra logic sẽ như sau:

IF @Param1 IS NOT NULL
SELECT... FROM dbo.Tblxxx WHERE Col1= @Param1
ELSE
SELECT TOP 200 ... FROM dbo.Tblxxx -- TOP 200 để khống chế số bản ghi khi không có tham số

Tức là khi tham số vào @Param1 được truyền giá trị thì ta lọc các bản ghi dựa trên giá trị đó, còn nếu không (NULL) thì ta không lọc. Tuy nhiên cách làm trên không thể mở rộng với nhiều tham số, vì số nhánh chương trình sẽ tăng rất nhanh (2^n). Ví dụ nếu ta có hai tham số @Param1 và @Param2, đoạn code sẽ giống như thế này:

IF (@Param1 IS NOT NULL) AND (@Param2 IS NOT NULL)
...
ELSE IF (@Param1 IS NOT NULL) AND (@Param2 IS NULL)
...
ELSE IF (@Param1 IS NULL) AND (@Param2 IS NOT NULL)
...
ELSE
...

Không những code rất cồng kềnh mà nó còn rất khó bảo trì. Nếu đến một lúc ta cần thêm một tham số thứ ba @Param3, sẽ tốn rất nhiều công để sửa lại và viết thêm vào đoạn code trên. Hoặc nếu cần thêm một cột vào kết quả đầu ra, ta sẽ phải thêm vào tất cả các nhánh của chương trình. Có thể nói cách làm trên là không khả thi trong đa số trường hợp.

Bài viết này giới thiệu hai cách làm có thể áp dụng trên thực tế, nhưng trước hết tôi nói qua về ví dụ sẽ được sử dụng trong bài.Ta có một database về các bộ phim đã được sản xuất, và giả sử ta cho phép tìm kiếm theo các tiêu chí sau:

@Tenphim:Tên của bộ phim

@NamsxMin: Từ năm sản xuất

@NamsxMax: Đến năm sản xuất

@Nuocsx: Nước sản xuất

@Theloai: Thể loại phim (hành động/hài/chính kịch…)

Cách làm thứ nhất

CREATE PROCEDURE dbo.TimKiemPhim_1
    @Tenphim NVARCHAR(50),
    @NamsxMin INT,
    @NamsxMax INT,
    @Nuocsx NVARCHAR(50),
    @Theloai NVARCHAR(50)
AS
SELECT P.*
FROM dbo.Phim P
WHERE (@Tenphim IS NULL OR P.Tenphim like '%'+@Tenphim+'%')
AND (@NamsxMin IS NULL OR P.Namsx >= @NamsxMin)
AND (@NamsxMax IS NULL OR P.Namsx <= @NamsxMax)
AND (@Nuocsx IS NULL OR P.Nuocsx = @Nuocsx)
AND (@Theloai IS NULL OR P.Theloai = @Theloai)

Trong cách làm này ta khai thác trị chân lý của mệnh đề OR – khi tham số @p là NULL, tức là “@p IS NULL” đúng, thì cả mệnh đề ở mỗi dòng AND đúng. Do đó chỉ khi @p được truyền giá trị thì điều kiện tìm kiếm mới được thực hiện. Như vậy code trông đã gọn hơn, mà mở rộng cũng rất dễ dàng, khi cần bổ sung thêm một tham số thì ta chỉ cần viết thêm một dòng lệnh.

Có những trường hợp khi một tham số nào đó được cung cấp ta cần truy nhập vào bảng khác . Giả sử có thêm tham số @TenDienvien để tìm các phim có một diễn viên nào đó tham gia; và giả sử bảng dbo.Dongphim (Đóng phim) chứa tên các diễn viên tham gia đóng phim và quan hệ của bảng dbo.Phim với bảng này là 1-nhiều (mỗi phim có nhiều diễn viên tham gia). Ta có thể thêm đoạn code sau:

AND (@TenDienvien IS NULL OR
     EXISTS(SELECT 1 FROM dbo.Dongphim D
            WHERE D.PhimID = P.PhimID AND D.TenDienvien like '%'+@TenDienvien+'%')
)

Trong một số tình huống, thủ tục trên có thể chạy rất nhanh ở lần thực hiện đầu nhưng lại chậm hơn nhiều ở lần tiếp theo, khi các tham số tìm kiếm khác với lần đầu. Nguyên nhân của nó là hiện tượng “parameter sniffing” (tôi sẽ nói ở dịp khác). Một cách để khắc phục là thêm lựa chọn “WITH RECOMPILE” vào đoạn khai báo thủ tục, ngay trước từ khóa AS.

Cách làm thứ hai

Dùng sql động, xây dựng chuỗi sql động dựa trên các tham số đầu vào và thực thi chuỗi sql đó.

CREATE PROCEDURE dbo.TimKiemPhim_2
    @Tenphim NVARCHAR(50) = NULL,
    @NamsxMin INT = NULL,
    @NamsxMax INT = NULL,
    @Nuocsx NVARCHAR(50) = NULL,
    @Theloai NVARCHAR(50) = NULL
AS
DECLARE @SqlStr NVARCHAR(MAX),
        @ParamList NVARCHAR(2000)
SELECT @SqlStr = '
       SELECT P.*
       FROM dbo.Phim P
       WHERE (1=1)
       '
IF @Tenphim IS NOT NULL
       SELECT @SqlStr = @SqlStr + '
              AND (P.Tenphim like '''%'+@Tenphim2+'%''')
              '
IF @NamsxMin IS NOT NULL
       SELECT @SqlStr = @SqlStr + '
              AND (P.Namsx >= @NamsxMin2)
              '
IF @NamsxMax IS NOT NULL
       SELECT @SqlStr = @SqlStr + '
             AND (P.Namsx <= @NamsxMax2)
             '
IF @Nuocsx IS NOT NULL
       SELECT @SqlStr = @SqlStr + '
              AND (P.Nuocsx = @Nuocsx2)
              '
IF @Theloai IS NOT NULL
       SELECT @SqlStr = @SqlStr + '
              AND (P.Theloai = @Theloai2)
              '
SELECT @Paramlist = '
       @Tenphim2 NVARCHAR(50),
       @NamsxMin2 INT,
       @NamsxMax2 INT,
       @Nuocsx2 NVARCHAR(50),
       @Theloai2 NVARCHAR(50)
       '
EXEC SP_EXECUTESQL @SqlStr,
                   @Paramlist,
                   @Tenphim,
                   @NamsxMin,
                   @NamsxMax,
                   @Nuocsx,
                   @Theloai

Với cách làm này việc viết code có rườm rà và khó theo dõi hơn. Tuy nhiên trong một số trường hợp cách này lại có ưu điểm hơn cách thứ nhất:

1. Thủ tục sp_executesql sẽ lưu kế hoạch thực thi cho mỗi bộ tham số, do đó nó giải quyết vấn đề “parameter sniffing” một cách thông minh hơn so với cách thứ nhất (luôn luôn phải biên dịch lại).

2. Trong trường hợp ta cần SELECT dữ liệu từ các bảng khác nhau tùy theo tham số được truyền. Ví dụ ta có tham số @Phimkinhdien kiểu BIT, khi bằng 1 thì cần SELECT từ bảng dbo.Phimkinhdien, khi bằng 0 thì SELECT từ bảng dbo.Phim như trên. Với cách làm dùng sql động ta có thể dễ dàng làm như sau:

...
SELECT @SqlStr = '
              SELECT P.*
              FROM ' + CASE WHEN @Phimkinhdien=1 THEN 'dbo.Phimkinhdien' ELSE 'dbo.Phim' END+'
              WHERE (1=1)
              '

Với cách làm thứ nhất, ta không có cách nào khác là tạo thêm một nhánh, trong đó lặp lại câu lệnh SELECT và thay bảng dbo.Phim bằng dbo.Phimkinhdien

Bổ sung: một số bạn viết thư hỏi dùng EXEC thay cho sp_executesql có được không. Câu trả lời là bạn nên dùng sp_executesql và tránh EXEC, vì sp_executesql tăng khả năng dùng lại kế hoạch thực thi, trong khi EXEC luôn dẫn đến thủ tục phải biên dịch lại. Một lý do nữa là sp_executesql tránh được lỗi SQL injection, EXEC thì gặp lỗi này. Tôi sẽ trở lại vấn đề so sánh giữa sp_executesql và EXEC trong một dịp khác.
Một bạn nêu trường hợp các cột cần trả về thay đổi tùy theo giá trị của tham số, ví dụ nếu tham số @p=1 thì SELECT các cột col1, col2, col3, còn nếu @p=2 thì SELECT col4, col5, col6. Khi đó cách làm thứ hai ở trên có thể áp dụng dễ dàng, và đây cũng là một trường hợp nó có ưu thế hơn cách làm thứ nhất.




Tags: , , , , , , , , ,

42 Comments
Posted on 20/5/2010 | Categories: SQL Server Programming, Sql động

Các bài viết tương tự

Comments
  • Khoa Nguyen Anh (03/06/2010 1:23 am)

    Tôi hay dùng thứ nhất, kết hợp OR. Tuy nhiên tôi hay để ngược lại

    AND (P.Namsx <= @NamsxMax OR @NamsxMax IS NULL)

    Vì hình như theo tôi được biết thì SQL kiểm tra từng mệnh đề thì nó thực hiện từ phải sang trái. Theo tôi hiểu trong trường hợp tham số NULL, với mỗi row thì khi thấy "@NamsxMax IS NULL" thì lập tức cả cụm OR trên trả về TRUE và row đó được chọn luôn. SQL không cần check điều kiện bên trái nữa.

    Vậy tôi hay để điều kiện tham số NULL hay tương tự bên phải.

  • vuht2000 (11/06/2010 11:57 am)

    @Khoa: ý bạn nêu rất hay, trước nay tôi không để ý đến điều này (thứ tự xử lý mệnh đề từ phải sang trái). Bạn có nguồn nào nói thêm về chi tiết này không?

  • tuấn (29/11/2010 7:52 am)

    Cách thực hiện khá hay, k những áp dụng cho search mà có thể dùng cho cả các trường hợp select dữ liệu tổng quát đơn giản hay dùng nữa. Tks bạn đã chia sẻ các bài viết hữu ích.

  • Lê Việt Dũn (30/11/2010 7:14 am)

    Bài viết khá hay. Trang web này thật sự rất hữu ích về nội dung. Cách bố trí nội dung bài viết cũng rất rõ ràng. Thanks.

  • armhidden (08/02/2011 10:55 pm)

    Cảm ơn các anh đi trước, quả là kiến thức rất hay!

  • vietnn-it (01/03/2011 1:28 am)

    You nice!

    Tks!!!

  • BaoAnh (28/03/2011 8:02 am)

    bài viết rất hay,nhưng làm sao để có thể lấy dự liệu đã search dc đưa ra datagridview,có thể hướng dẫn cho mình thêm cách lấy du liệu ra ko.thanks

  • quang thai (25/04/2011 12:12 am)

    thanks ban nha

  • vô danh (13/05/2011 6:45 am)

    bài viết rất hay,nhưng làm sao để có thể lấy dự liệu đã search dc đưa ra datagridview,có thể hướng dẫn cho mình thêm cách lấy du liệu ra ko.thanks
    ===>>Có dữ liêu rồi mà không biết làm sao để đưa nó vào grid ah?
    Cho nó vào 1 table chẳnh hạn rồi gán datasource bằng cái table đó!

  • chip07 (07/07/2011 11:47 pm)

    1.
    bài viết rất hay và thực sự công phu, nhưng hình như bác nhầm tí xíu ở chỗ

    IF @Tenphim IS NULL
    SELECT @SqlStr = @SqlStr + ‘
    AND (P.Tenphim like ”’%'+@Tenphim2+’%”’)

    đúng ra phải là ‘IS NOT NULL’ phải ko ạ?

    tính em tỉ mẩn thế thôi, nếu e nhầm đừng ném đá nhé (T_T)

    2.
    Còn về trường hợp bạn Khoa nói, đúng là mình cũng đã đọc đâu đó rồi. Bình thường mình cũng ko nhớ, toàn dịch logic từ trái sang, hôm nay đọc bài này tự nhiên nhớ ra.
    Về nguồn dẫn chứng thì phải tìm cơ, nhưng có cách này (là kinh nghiệm bản thân trải nghiệm thôi):

    Mình viết procedure, trong đó có dòng code có 2 vế điều kiện, khi dịch OK; khi chạy được nửa chừng nó bảo lỗi (vì SQL là chạy code đồng thời mà).
    Thường gặp trường hợp này là khi ta dùng SQL động để SELECT dữ liệu trên các bảng có cấu trúc tương đồng VÀ có một vài ngoại lệ, và nếu để test, ta cố tình để vế đk bên trái (hay phải nhỉ (>.<) xin lỗi nhưng mà ko nhớ rõ) bị lỗi; lưu ý là phải tính trường hợp những bảng đầu thì OK, đến bảng ngoại lệ có thể sẽ phát sinh lỗi.

    Trình bày lằng nhằng quá, nhưng đúng là mình có gặp, để nao gặp lại mình sẽ post code lên đây nhé (hiện tại ko nhớ ra, lúc có lỗi thì bận gỡ lỗi ngay lập tức mà)

  • Vũ Huy Tâm (08/07/2011 8:32 am)

    @Chip07: 1. Đúng rồi, phải là “IS NOT NULL”. Tôi sửa lại rồi (tệ quá, thế mà cũng nhầm :) ). Thanks bạn

  • nguyen (06/05/2012 11:46 pm)

    mấy bác cho em hỏi cách chạy cái thủ tục thứ 2 vơi ạ,
    em mới vào nghề nên chẳng biết chạy nó thế nào,mong các bác chỉ cho em

  • nguyen (06/05/2012 11:57 pm)

    em run cái thủ tục thứ 2 thì gặp lỗi

    Msg 214, Level 16, State 2, Procedure sp_executesql, Line 1
    Procedure expects parameter ‘@statement’ of type ‘ntext/nchar/nvarchar’.

    em nghĩ chắc là em ko biết run cái này, bác nào biết chỉ dùm em luôn nha.

  • ngocvu90 (17/08/2012 3:17 am)

    đã text cách 1 chạy nhưng không ra kết quả.. đề nghị mod kiểm tra

  • ngocvu90 (17/08/2012 3:42 am)

    đã text không chạy ở chổ (@NamsxMin IS NULL OR P.Namsx >= @NamsxMin)
    tất cã sửa lại là @NamsxMin=’ ‘ thì được còn để @NamsxMin IS NULL không chạy ra kết quả
    không biết vì sao…

  • ngocvu90 (17/08/2012 3:52 am)

    đã hiểu ra vấn đề. @NamsxMin=’ ‘ —>rỗng có ngĩa là giá trị rỗng
    còn @NamsxMin is null —->tồn tại hay không tồn tại… thiệt là cái tình ý mà 2 cái này khác nhau hoàn toàn

  • Nguyen Quynh (08/01/2013 10:47 am)

    Có phải dùng cách 1 Index sẽ mất tác dụng, trong khi đó, nếu dùng cách 2 thì index phát huy tác dụng??? Vì mình thường dùng cách 1.

    • Lucario (08/01/2013 10:50 pm)

      Theo mình nghĩ thì không phải dùng cách 1 thì Index bị mất tác dụng.
      Mà việc sử dụng Index hay không, phụ thuộc vào lần chạy đầu tiên thủ tục này. Do lần đầu tiên chạy, SQL Server sẽ sinh ra 1 kế hoạch thực thi phù hợp với các tham số truyền vào (trong đó tất nhiên có cả việc quyết định sử dụng Index hay không). Và những lần chạy tiếp theo, theo mặc định, SQL Server sẽ sử dụng luôn kế hoạch thực thi đã dùng cho lần chạy đầu tiên để áp dụng cho các lần chạy tiếp theo. Và tất nhiên, kế hoạch thực thi này không phải lúc nào cũng là tối ưu nhất đối với các đầu vào khác nhau.
      Do vậy mới có hiện tượng là có thể chạy rất nhanh ở lần thực hiện đầu nhưng lại chậm hơn nhiều ở lần tiếp theo, khi các tham số tìm kiếm khác với lần đầu.
      Ý kiến e như vậy, không biết đúng ko :d

  • NaCl (08/03/2013 9:07 am)

    Cho em hỏi:

    create proc SP_TimKiemND
    @HT nvarchar(100)=NULL,
    @GT nvarchar(3)=null,
    @NhomND int=null
    as
    declare @SqlStr nvarchar(Max),
    @ParaList nvarchar(2000)
    select @SqlStr=’
    select NguoiDung.MaND [Mã nhóm người], NguoiDung.HoTenDayDu [Họ tên],
    NguoiDung.GioiTinh [Giới tính],NguoiDung.MatKhau [Mật khẩu],NguoiDung.DiaChi [Địa chỉ],
    NguoiDung.SDT [Số điện thoại],NguoiDung.Email,NguoiDung.NgayTao_ND [Ngày tạo], NguoiDung.TgianSua [Ngày sửa],NhomND.TenNhom [Tên nhóm]
    from NguoiDung , NhomND,ChiTiet_Nhom_ND
    where NguoiDung.MaND=ChiTiet_Nhom_ND.MaND and ChiTiet_Nhom_ND.MaNhom= NhomND.MaNhom’
    if @HT !=”
    select @SqlStr=@SqlStr+’
    AND (NguoiDung.HoTenDayDu like ”’%'+@HT1+’%”’)’
    if @GT !=”
    select @SqlStr=@SqlStr+’ and (NguoiDung.GioiTinh=@GT1)’
    if @NhomND!=”
    select @SqlStr=@SqlStr+’and (NhomND.MaNhom=@NhomND1)’

    select @ParaList=’@HT1 nvarchar(100),
    @GT1 nvarchar(3),
    @NhomND1 int’
    exec SP_EXECUTESQL @SqlStr,
    @ParaList,
    @HT,
    @GT,
    @NhomND

    Báo lỗi :
    Msg 402, Level 16, State 1, Procedure SP_TimKiemND, Line 18
    The data types varchar and varchar are incompatible in the modulo operator.
    là sao ạ, em làm giống hệt anh hướng dẫn mà*_*

  • NaCl (08/03/2013 9:09 am)

    select @SqlStr=@SqlStr+’
    AND (NguoiDung.HoTenDayDu like ”’%'+@HT1+’%”’)’
    nó bị lỗi chỗ đó, thì sửa sao ạ

    • Vũ Huy Tâm (21/03/2013 8:58 am)

      Dùng dấu nháy kép (“) là không đúng (không biết bạn dùng hay là wordpress tự động sửa lại. Bạn cần viết như thế này (lưu ý hai dấu nháy đơn liền nhau chứ không phải dấu kép):

      SELECT @SqlStr=@SqlStr+'
      AND (NguoiDung.HoTenDayDu like ''%'+@HT1+'%'')'
      • NaCl (25/03/2013 12:42 pm)

        Em cám ơn^^

      • nxsql (07/04/2013 11:52 am)

        Như vậy viết hình như vẫn ko đúng bạn ạ.
        Viêt thế này sai: P.Tenphim like ”’%'+@Tenphim2+’%”’
        – Hệ thống sẽ báo “The data types varchar and varchar are incompatible in the modulo operator.”

        Nếu viết thế sai: NguoiDung.HoTenDayDu like ”%’+@HT1+’%”)’
        – Thì phải khai báo @HT1 nữa chứ. nhưng theo mình hiểu thì @HT1 sẽ là paralist chứ nhỉ. mình vẫn chưa hiểu.

      • Chu Thị Thùy (26/12/2014 4:15 am)

        Em cũng bị gặp lỗi giống bạn NaCL
        Lỗi:The data types varchar and varchar are incompatible in the modulo operator.
        Nếu sửa lại như anh thì phải khai báo thêm tham số @HT1 nhưng vẫn chưa chạy đúng được ạ.

  • nguoihanoi (22/03/2013 1:08 am)
    Tôi hay dùng thứ nhất, kết hợp OR. Tuy nhiên tôi hay để ngược lại
     
    AND (P.Namsx &lt;= @NamsxMax OR @NamsxMax IS NULL)
     
    Vì hình như theo tôi được biết thì SQL kiểm tra từng mệnh đề thì nó thực hiện từ phải sang trái. Theo tôi hiểu trong trường hợp tham số NULL, với mỗi ROW thì khi thấy &quot;@NamsxMax IS NULL&quot; thì lập tức cả cụm OR trên trả về TRUEROW đó được chọn luôn. SQL không cần CHECK điều kiện bên trái nữa.
     
    Vậy tôi hay để điều kiện tham số NULL hay tương tự bên phải.

    Trong trường hợp này trái phải đều như nhau

  • TonyBui (06/06/2013 6:57 am)

    Trước hết xin cảm ơn tác giả bài viết!

    Bài viết rất hay và hữu ích.
    Mình đã tìm hiểu vấn đề này khá nhiều thời gian. Thú thực là search toàn tiếng Anh.
    Tuy nhiên, kết quả search bằng tiếng Việt thật đáng kinh ngạc.

    Mình rất quan tâm đến bảo mật trong lập trình.
    Trước đây hay xử lý chuỗi trước khi thực hiện EXEC SQL.

    Đối với các lệnh Insert, Update, Delete thì đã dùng từ lâu.
    Nhưng đối với Search vẫn thường xử lý chuỗi đầu vào rồi đưa vào câu lệnh tìm kiếm ngay trong code. Vẫn rất nguy hiểm đối với hacker chuyên nghiệp.

    Giờ đã có thêm HAI cách nữa để xử lý rồi.

    Một lần nữa, cảm ơn tác giả và các bạn trong diễn dàn sqlviet rất nhiều!

  • Phước Nguyễn (08/07/2013 10:14 am)

    Trước hết cảm ơn tác giả về bài viết. nhưng từ chỗ ở cách viết thứ 2 này mình chưa hiểu mong tác giả hồi đáp.

    thứ nhất là các giá trị trong @Paramlist lấy từ đâu

           @Tenphim2 NVARCHAR(50),
           @NamsxMin2 INT,
           @NamsxMax2 INT,
           @Nuocsx2 NVARCHAR(50),
           @Theloai2 NVARCHAR(50)


    thứ hai là chỗ này mình không hiểu mong tác giả giải thích rõ ràng hơn. xin cảm ơn

    EXEC SP_EXECUTESQL @SqlStr,
                       @Paramlist, 
                       @Tenphim,   -- tại sao không phải là @tenphim2=@tenphim ?? tương tự thắc mắc cho các câu ở dưới
                       @NamsxMin,   
                       @NamsxMax,
                       @Nuocsx,
                       @Theloai
  • Vũ Huy Tâm (11/07/2013 1:23 pm)

    Trong lệnh EXEC SP_EXECUTESQL thì @SqlStr là chuỗi chứa lệnh cần thực hiện, chuỗi này chứa các tham số và @Paramlist là chuỗi chứa các tham số này. Tiếp theo đó là các giá trị truyền vào cho các tham số tương ứng trong @Paramlist.
    Trong @SqlStr và @Paramlist tôi dùng @Tenphim2, @NamsxMin2… để dễ hình dung mỗi tham số ánh xạ với giá trị nào truyền vào, chứ tôi có thể thay bằng @abc, @xyz, hoặc trùng với các tham số bên ngoài @Tenphim, @NamsxMin… cũng được.
    @Paramlist chứa các tham số dùng trong @SqlStr và chúng tạo thành 1 ngữ cảnh riêng độc lập với ngữ cảnh bên ngoài câu lệnh EXEC SP_EXECUTESQL nên các tham số cũng độc lập theo. Ví dụ sau đây đơn giản hơn hy vọng giúp bạn hiểu được:

    CREATE TABLE Test(id INT, VALUE VARCHAR(10))
    INSERT INTO Test VALUES(1,'abc')
    INSERT INTO Test VALUES(2,'def')
     
    DECLARE @i INT, @SQL NVARCHAR(1000), @plist NVARCHAR(100)
    SET @i = 1
    SET @SQL = N'SELECT * FROM Test WHERE  id = @x'
    SET @plist = '@x INT'
     
    EXEC SP_EXECUTESQL @SQL, @plist, @i --dùng tham số ở ngoài để truyền cho câu lệnh
    EXEC SP_EXECUTESQL @SQL, @plist, 2 --truyền thẳng giá trị cho câu lệnh

    Ở ví dụ trên, @SQL là một câu lệnh select dùng tham số @x, tham số @x này được khai báo trong @plist, và được truyền vào qua tham số thứ ba trong lệnh EXEC SP_EXECUTESQL. Vì @SQL chỉ dùng 1 tham số, nên @plist cũng chỉ chứa 1 tham số, và sau @plist cũng chỉ có 1 giá trị được truyền vào. Nếu @SQL dùng 1 tham số, @plist cũng phải khai báo 1 tham số, và sau @plist cũng phải có 2 giá trị được truyền vào.
    Về câu hỏi thứ hai: tôi có thể dùng @tenphim2 = @tenphim… và kết quả không có gì khác. Cách tôi viết trong bài là viết tắt.

    • Phước Nguyễn (14/07/2013 4:15 am)

      Mình hiểu rồi. thanks anh tâm nhiều lắm.

  • Vĩ Hùng (01/02/2015 3:28 am)

    Chào a Vũ Duy Tâm, a có nick yahoo hay Facebook gì k a, cho e hỏi vài chút thắc mắc về Proc cái , vì bài tập trong trường đề đọc em không hiểu muốn nhờ anh giải thích giùm ^^~

  • XO NGUYEN (09/03/2015 12:37 pm)

    Chào anh Tâm, các bạn,
    Qua nhiều project tham gia, đặc biệt có một số project đòi hỏi performance thì mình thấy cách 2 mình thích dùng hơn.
    Mình cũng thử phân tích câu truy vấn dạng:

    SELECT * FROM TABLE WHERE (col1 =@param1 or @param1 IS null) and (col2 = @param2 or @param2 IS null)

    Cách này trong bảng dữ liệu nhỏ, không có vấn đề gì nhưng với bảng dữ liệu lớn, mình test thấy nếu @param1 is null thì câu truy vấn lại có vẻ chậm hơn so với ko cho @param1 . Tức nếu @param1 is null, @param2 null thì câu truy vấn

    SELECT * FROM TABLE WHERE (col1 =@param1 or @param1 IS null) and (col2 = @param2 or @param2 IS null)

    Chạy chậm hơn:

    SELECT * FROM TABLE WHERE  (col2 = @param2 or @param2 IS null)
  • Ken Nguyễn (15/07/2016 4:12 am)

    Mình viết dynamic sql,tới đoạn code tìm kiếm ngày bảo hành của product theo thời gian từ ngày đến ngày mình viết như sau :

    IF @TuNgay IS not null
    BEGIN
    SET @SqlStr=@SqlStr+'and (p.NgayBatDau &gt;= @TuNgay2)'
    END
    IF @DenNgay IS not null
    BEGIN
    SET @SqlStr=@SqlStr+'and (p.NgayKetThuc &lt;= @DenNgay2)&#039;
    end

    Khi thực thi SP thì p.NgayKetThuc không lấy được các ngày = @DenNgay2, ví dụ :

    p.NgayKetThuc <= '2016/07/07' : thì nó chỉ lấy các ngày bé hơn 07/07 mà thôi không lấy luôn ngày 07/07.

    • Vũ Huy Tâm (19/07/2016 3:28 pm)

      ’2016/07/07′ nghĩa là đúng lúc 0h sáng ngày đó, nên nếu ngày kết thúc trong database là ’2016/07/07 11:00:00′ (11h sáng) thì lúc đó nó lớn hơn ’2016/07/07′ và không thỏa mãn nữa rồi. Bạn sửa lại thành:
      p.NgayKetThuc <= ’2016/07/08′, hoặc
      p.NgayKetThuc <= ’2016/07/07 23:59:59′

  • Ken Nguyễn (18/07/2016 7:07 am)

    Chào Tâm,

    cho mình hỏi : Làm cách nào để gọi được Dynamic Sql này lên MVC bằng Entity Framework vậy ?

    • Vũ Huy Tâm (19/07/2016 3:28 pm)

      mình ko dùng MVC nên ko biết

    • tung (07/10/2016 10:52 pm)

      Bạn gọi proc thông qua Entity Framework thôi

Leave a Reply

Hướng dẫn: Để nhập mã T-SQL bạn dùng thẻ <pre lang="tsql"> và </pre>.
Ví dụ: <pre lang="tsql">SELECT * FROM MyTable</pre>