PDA

View Full Version : Giúp em với trigger rắc rối vô cùng



nguyenviettho
05-05-2011, 23:29
Em có 1 bảng tbl_bangdiem với các trường như sau :
Ma_BD int tự tăng,
Ma_SV char (khóa phụ link đến bảng khác),
Ma_mon int (khóa phụ link đến bảng khác),
Hoc_ky int,
Lan_thi int giá trị mặc định =1,
Diem_DD (điểm điểm danh) float giá trị mặc định =5,
Diem_DK (điểm điều kiện) float giá trị mặc định =3,
Diem_thi float giá trị mặc định =0

Bài toán của em bao h cũng nhập Diem_DD và Diem_DK trước rồi sau đó mới đến điểm thi. Ở đây chưa quan tâm đến điểm thi vội. Nhu cầu bài toán của em như sau : khi nhập điểm Diem_DD và Diem_DK (insert vào bảng tbl_bangdiem) thì sẽ có trigger kiểm tra nếu Diem_DD <5 hoặc Diem_DK <3 thì sẽ tự động insert thêm 1 bảng ghi với Lan_thi=+2 còn các thông tin như Ma_SV, Ma_mon,Hoc_ky thì giống như bản cũ (có thể chưa quan tâm ở đây) . em có demo 1 trigger đã đáp ứng đc gần hết mọi yêu cầu của đầu bài tuy nhiên có 1 lỗi là bản ghi sau nó ko lấy được giá trị Ma_SV từ bản ghi trước mà toàn lấy =1 .


set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER trigger [dbo].[kiem_tra_DK_thi]
on [dbo].[tbl_bangdiem]
for insert
as
begin
declare @diem_cc float
declare @diem_dk float
declare @Ma_SV char
declare @Ma_mon char
declare @Hoc_ky int
declare @Lan_thi int
select @diem_dk=Diem_DK from inserted
select @diem_cc = Diem_DD from inserted
select @Ma_SV = Ma_SV from inserted
select @Ma_mon = Ma_mon from inserted
select @Hoc_ky = Hoc_ky from inserted
select @Lan_thi = Lan_thi from inserted
if @diem_cc < 5 or @diem_dk<3
begin
insert into tbl_bangdiem(Ma_SV,Ma_mon,Hoc_ky,Lan_thi)
values(@Ma_SV,@Ma_mon,@Hoc_ky,(@Lan_thi+1))
end
end



[=========> Bổ sung bài viết <=========]

uppppppppppppppppppppppppppppppppppppppppp

[=========> Bổ sung bài viết <=========]

không có ai à :(..................

zxcongducxz
06-05-2011, 19:55
CREATE DATABASE vd
GO
USE vd
GO
CREATE TABLE tbl_bangdiem
(
Ma_BD int IDENTITY(1,1)
,Ma_SV char
,Ma_mon int
,Hoc_ky int
,Lan_thi int
,Diem_DD float
,Diem_DK float
,Diem_thi float
)
GO
CREATE TRIGGER trig1 ON tbl_bangdiem
INSTEAD OF INSERT
AS
BEGIN
DECLARE @Ma_SV char=(SELECT Ma_SV FROM INSERTED)
DECLARE @Ma_mon int=(SELECT Ma_mon FROM INSERTED)
DECLARE @Hoc_ky int=(SELECT Hoc_ky FROM INSERTED)
DECLARE @Lan_thi int=(SELECT Lan_thi FROM INSERTED)
DECLARE @Diem_DD float=(SELECT diem_DD FROM INSERTED)
DECLARE @Diem_DK float=(SELECT Diem_DK FROM INSERTED)
DECLARE @Diem_thi float=(SELECT Diem_thi FROM INSERTED)
IF @Diem_DD<5 OR @Diem_DK<3
INSERT INTO tbl_bangdiem VALUES(@Ma_SV,@Ma_mon,@Hoc_ky,@Lan_thi+1,@Diem_DD, @Diem_DK,@Diem_Thi)
ELSE
INSERT INTO tbl_bangdiem VALUES(@Ma_SV,@Ma_mon,@Hoc_ky,@Lan_thi,@Diem_DD,@D iem_DK,@Diem_Thi)
END


cái này mình làm trên SQL 2008, hok bik đúng ý không

vuht2000
07-05-2011, 01:57
cách làm của zxcongducxz chưa tính đến trường hợp nhiều dòng được insert cùng nhau

chip07
07-05-2011, 23:09
CREATE TRIGGER trig1 ON tbl_bangdiem
FOR INSERT
AS
BEGIN
IF EXISTS (SELECT 1 FROM inserted WHERE Diem_DD < 5 OR Diem_DK < 3)
INSERT INTO tbl_BangDiem (Ma_SV, Ma_mon, Hoc_ky, Lan_thi)
SELECT Ma_SV, Ma_mon, Hoc_ky, Lan_thi + 2
FROM inserted
END



cách làm của zxcongducxz chưa tính đến trường hợp nhiều dòng được insert cùng nhau

số bản ghi trong bảng inserted và deleted luôn <= 1 . (^_^)

hungbv
08-05-2011, 11:04
Bạn muốn trigger xử lý được nhiều bản ghi bạn cần sử dụng đến bảng tạm, Khai báo bảng tạm và insert dữ liệu từ inserted vào bảng này và dùng kỹ thuật loại trừ theo vòng lặp

chip07
08-05-2011, 17:37
Bạn muốn trigger xử lý được nhiều bản ghi bạn cần sử dụng đến bảng tạm, Khai báo bảng tạm và insert dữ liệu từ inserted vào bảng này và dùng kỹ thuật loại trừ theo vòng lặp

số bản ghi trong bảng inserted và deleted của trigger chắc chắn luôn chỉ có 1 (nếu có), nó chỉ lưu trữ dữ liệu của bản ghi hiện đang được insert/delete/update

hungbv
08-05-2011, 20:38
số bản ghi trong bảng inserted và deleted của trigger chắc chắn luôn chỉ có 1 (nếu có), nó chỉ lưu trữ dữ liệu của bản ghi hiện đang được insert/delete/update

oh. Bạn đã nhầm rồi. Khi bạn dùng trigger insert/delete/update nhiều bản ghi (Ví dụ dang


insert into TB_Table1
Select * from TB_Table2

Mình hay gọi là insert/delete/update theo bó thì trong bảng inserted hoặc deleted sẽ lưu tất cả các dữ liệu đã thay đổi nhưng nếu bạn không đưa nó vào bảng tem bạn chỉ lấy được bản ghi đầu tiên (Hay cuỗi cùng mình không nhớ rõ) của bó này. Mình sẽ viết cho bạn một ví dụ cụ thể minh họa việc cập nhật dữ liệu theo bó bằng trigger trên http://hmweb.com.vn

[=========> Bổ sung bài viết <=========]

Đã viết xong hướng dẫn
http://hmweb.com.vn/sql-server-trigger-cap-nhat-du-lieu-hang-loat/772/pro/71/61/cntt.aspx

chip07
09-05-2011, 11:30
@hungbv: mình đã test, đúng là nó thực hiện nhiều bản ghi cùng một lúc. Mình nghĩ trước đây mình đã test rồi, nhưng có lẽ mình đã không test cẩn thận. Cảm ơn hungbv đã nhắc nhở, mình biết thêm về trigger.

ah, và đây là code test (>.<)



CREATE TABLE tblXuat
(
ID bigint IDENTITY(1,1),
MS nvarchar(50),
SoLuong money
)

GO

CREATE TABLE tblXuat_TestTrigger
(
ID bigint IDENTITY(1,1),
Loai nvarchar(50),
IDXuat bigint,
MS nvarchar(50),
SoLuong money
)

GO

CREATE PROCEDURE spTestTrigger
AS
BEGIN
INSERT INTO tblXuat_TestTrigger (Loai, IDXuat, MS, SoLuong)
SELECT 'I', ID, MS, SoLuong
FROM #btInserted

INSERT INTO tblXuat_TestTrigger (Loai, IDXuat, MS, SoLuong)
SELECT 'D', ID, MS, SoLuong
FROM #btDeleted
END

GO

CREATE TRIGGER tg_tblXuat
ON tblXuat
FOR INSERT, UPDATE, DELETE
AS
BEGIN
SELECT 'I' Loai, ID, MS, SoLuong
INTO #btInserted
FROM inserted

SELECT 'D' Loai, ID, MS, SoLuong
INTO #btDeleted
FROM deleted

EXEC spTestTrigger
END

GO

-- test
select 'test: insert'

insert into tblXuat (MS, SoLuong)
select 'a', 1

insert into tblXuat (MS, SoLuong)
select 'b', 2

insert into tblXuat (MS, SoLuong)
select 'c', 3

insert into tblXuat (MS, SoLuong)
select 'd', 4

select * from tblXuat
select * from tblXuat_TestTrigger

select 'test: update: SoLuong = SoLuong + ID'

update tblXuat
set SoLuong = SoLuong + ID
where ID < 3

select * from tblXuat
select * from tblXuat_TestTrigger

select 'test: delete'

delete from tblXuat

select * from tblXuat
select * from tblXuat_TestTrigger

DROP TABLE tblXuat
DROP TABLE tblXuat_TestTrigger
DROP PROC spTestTrigger

vuht2000
09-05-2011, 22:26
Bạn thử đoạn này xem. Tôi dùng một câu select hoặc nếu muốn có thể tách làm hai và đưa điều kiện vào mệnh đề WHERE:


CREATE TRIGGER trig1 ON tbl_bangdiem
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO tbl_BangDiem (Ma_SV, Ma_mon, Hoc_ky, Lan_thi)
SELECT Ma_SV, Ma_mon, Hoc_ky,
CASE WHEN Diem_DD < 5 OR Diem_DK < 3 THEN Lan_thi + 2
ELSE Lan_thi END
FROM inserted
END