Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 триггер, отлов события.  [new]
NIIIK
Member

Откуда: Россия, Ростовская область, г. Таганрог
Сообщений: 1295
Есть список команий, дочерний список работников ссылается на компнию (многие к одному). С дочерними сущностями работников могу происходить insert/update/delete(физическое удаление).

Надо считать количество работников в компании триггером.

Как правильно сформировать условие триггера, для проверки надо ли вообще что-то апдейтить в родительской таблице?

 if not(
     update(companyID) or
     (select count(1)
        from inserted) = 0
     and
     (select count(1)
        from deleted
       where CompanyID is not null) > 0
     )
 begin
  return;
 end;

я пока использую такой код, но а как правильно?

меня вообще смущает функция update() ""системная"", которая возвращает сразу булевое значение без булевого типа данных, значение этой функции можно присвоить кому-нить?

Дальше после этого кода естественно, идёт фактическая проверка били ли изменены данные (значение поля companyID) (для каждой строки необходимо проверить, раз так уж работают триггера в МсСКЛ, что бы потом проблем не было) и формирование списка компаний у которых необходимо пересчитать количетсво работников.

Как правильно поставить условие?

Далее я покажу метод проверки "изменено ли фактическое значение" .... может тоже более быстродействующий есть.
5 янв 10, 17:51    [8150067]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
aleks2
Guest
Могет быть не стоит заниматься жесткими сексуальными извращениями?

1. Никогда не пишите триггеров.
2. Если очень надо написать триггер - см. п.1
3. Учитесь
(select count(1) from inserted)>0
надо писать так
exists(select * from inserted)

PS. Приведите определения таблиц и описание полей - сочинят БЕЗ триггеров.
5 янв 10, 18:03    [8150109]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
NIIIK
Member

Откуда: Россия, Ростовская область, г. Таганрог
Сообщений: 1295
Для формирования списка фактически изменённых

 begin
  select t.*
    from
  ( 
  select distinct
         i.CompanyID
    from inserted i
   inner
    join deleted d
      on i.employeeID = d.employeeID
     and i.CompanyID <> coalesce(d.CompanyID, -1)
   where i.CompanyID is not null

   union

  select distinct
         d.CompanyID
    from deleted d
   inner
    join inserted i
      on i.employeeID = d.employeeID
     and coalesce(i.CompanyID, -1) <> d.CompanyID
   where d.CompanyID is not null
   ) t

 end;

Соотвественно не нравится
1) union, но pivot/unpivot не нравятся больше
2) coalsece, но OR не нравится больше
5 янв 10, 18:09    [8150127]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
Леша777
Guest
3 тригера : отдельно на встаку, удаление, добавление быстрее чем один универсальный

Например :
CREATE TABLE dbo.Company (
                                         idCompany int not null PRIMARY KEY, 
                                         EmployeeNumber INT NOT NULL 
                                       )
CREATE TABLE dbo.Employee (
                                          idEmployee INT NOT NULL PRIMARY KEY
                                       , idCompany INT NOT NULL
                                      )


Пример тригеров:

AFTER INSERT :

UPDATE c 
SET c.EmployeeNumber = c.EmployeeNumber + x.num 
FROM dbo.Company c
JOIN 
       (
          SELECT i.idCompony 
                    ,COUNT(*)  [num]
          FROM Inserted i 
          GROUP BY i.idCompany 


       ) x 

AFTER UPDATE :

UPDATE c
SET 
     c.EmployeeNumber = c.EmployeeNumber - x.[num]

FROM dbo.Company c
JOIN 
       (
           SELECT d.idCompany 
                    , COUNT(*) [num]
          FROM Inserted i 
          JOIN Deleted d
             ON i.idEmployee = d.idEmployee
         WHERE d.idCopany <> i.idCompany 
        GROUP BY d.idCompany 
      ) x 


UPDATE c
SET 
      c.EmployeeNumber = c.EmployeeNumber + x.[num]
FROM dbo.Company c
JOIN 
       (
           SELECT i.idCompany 
                    , COUNT(*) [num]
          FROM Inserted i 
          JOIN Deleted d
             ON i.idEmployee = d.idEmployee
         WHERE d.idCopany <> i.idCompany 
        GROUP BY i.idCompany 
      ) x 


After Delete аналогично insert только делетед табл и знак поменять.
5 янв 10, 18:15    [8150149]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
NIIIK
Member

Откуда: Россия, Ростовская область, г. Таганрог
Сообщений: 1295
aleks2,
count или exists использовать чут ли вопрос не религии, не в том суть моего вопрос
Мне интересно как вообще его не использовать.

Триггер там надо, единственное что для высисления количества работников не хочу делать инремент/декременте, а тупо пересобрать агрегаткой, как это было бы сделано во вьюхе или в запросе.

Сам их не любитель, но тут модель упрощённая.

названия таблиц и названия полей непринципиально, я просто максимально простой пример отражающий суть моего вопроса использовал. Честно говоря у меня бы если бы писалось с нуля даже бы физического удаления не было бы таблицы работников. Вообще не понимаю как можно удалять как будто никогда и не было в данном случае.

Триггер нужен банально для повышения быстродействия. Что бы часто выбирающие значение пользователи получали редко меняющееся значения. Но суть вопроса и не в этом :)

вопрос оптимальности и максимального быстродействия
5 янв 10, 18:17    [8150157]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
aleks2
Guest
NIIIK
aleks2,
count или exists использовать чут ли вопрос не религии, не в том суть моего вопрос
Мне интересно как вообще его не использовать.

Триггер там надо, единственное что для высисления количества работников не хочу делать инремент/декременте, а тупо пересобрать агрегаткой, как это было бы сделано во вьюхе или в запросе.

Сам их не любитель, но тут модель упрощённая.

названия таблиц и названия полей непринципиально, я просто максимально простой пример отражающий суть моего вопроса использовал. Честно говоря у меня бы если бы писалось с нуля даже бы физического удаления не было бы таблицы работников. Вообще не понимаю как можно удалять как будто никогда и не было в данном случае.

Триггер нужен банально для повышения быстродействия. Что бы часто выбирающие значение пользователи получали редко меняющееся значения. Но суть вопроса и не в этом :)

вопрос оптимальности и максимального быстродействия


1. Чудо, прочти про ИНДЕКСИРОВАННЫЕ ПРЕДСТАВЛЕНИЯ (Indexed View). И не маразмируй.
2. count и exists различаются НЕ на уровне религии. Аминь.
5 янв 10, 18:20    [8150165]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
NIIIK
Member

Откуда: Россия, Ростовская область, г. Таганрог
Сообщений: 1295
Леша777,

так я наоборот пытаюсь в один объеденить. Не буду же я копи-пастом копировать кучу одинаковой логики т.п. ?

Сейчас простой пример показан, а так сложнее, потом начнётся модификация, кто-то что-то где-то начнёт менять и т. п.... За отдельные триггера спасибо, но как-то это "некрасиво" на мой личный субъективный вкус, есть ещё идеи?
5 янв 10, 18:20    [8150166]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
NIIIK
Member

Откуда: Россия, Ростовская область, г. Таганрог
Сообщений: 1295
Леша777,

К стате, я бы предпочёл полный пересчёт ... если бы частое изменение было бы, я бы пошёл на такой подсчёт, но всё равно с запуском через определённый интервал времени (или операций изменнения данных) обновлял бы.
5 янв 10, 18:23    [8150175]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
aleks2
Guest
Любит же наш народ жевать сопли

CREATE TABLE [CompanyEmployee] (
	[idCompany] [int] NOT NULL ,
	[idEmployee] [int] NOT NULL ,
	CONSTRAINT [PK_CompanyEmployee] PRIMARY KEY  CLUSTERED 
	(
		[idCompany],
		[idEmployee]
	)  ON [PRIMARY] 
) ON [PRIMARY]
GO

CREATE VIEW dbo.CompanyEmpCount
WITH SCHEMABINDING 
AS
SELECT     idCompany, COUNT_BIG (idEmployee) AS [Count]
FROM         dbo.CompanyEmployee
GROUP BY idCompany
GO

 CREATE  UNIQUE  CLUSTERED  INDEX [IX_CompanyEmpCount] ON [dbo].[CompanyEmpCount]([idCompany]) ON [PRIMARY]
GO

Только пользовать представление CompanyEmpCount надо с хинтом WITH(NOEXPAND), ежели у вас не Enterprise Edition.
5 янв 10, 18:29    [8150190]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
NIIIK
Member

Откуда: Россия, Ростовская область, г. Таганрог
Сообщений: 1295
aleks2
[quot NIIIK]aleks2,
...
1. Чудо, прочти про ИНДЕКСИРОВАННЫЕ ПРЕДСТАВЛЕНИЯ (Indexed View). И не маразмируй.
2. count и exists различаются НЕ на уровне религии. Аминь.


Я же вопрос сформулировал?

Я не зря спросил про триггер достаточно узко. Я тут уже две колонки создал с помощью триггеров только потому что не могу persisted computed column создать а всё из-за

Cannot create an index on a view or computed column because the compatibility level of this database is less than 80. Use sp_dbcmptlevel to raise the compatibility level of the database.

одно из полей "первые три цифры телефонного номера" что бы по коду телфонному искать можно было.

А на кой мне материализованная вьюха без кластерного индекса?!

А заказчик вообще не хочет менять уровень совместимости, хотя я ему сказал "Давай... я тебе все твои запросы на уровне приложения с внешними соеденениями =* и *= перепишу ..."

К стате, не факт что я использовал бы эту вьюху материализованную. Тем более я бы не сказал что там вообще вставок и изменений нет, я просто сказал что количество пользовательский запросов на выборку больше. Мне на этой базе пришлось как-то закешировать запрос, который выбирает 8 случайных записей из 100 тысяч, потому что проц. валился. В Триггере я могу хотя бы точнее управлять изменением данных ибо во вьюхи мне прийдётся всё равно написать запрос а-ля

create view vCompanyEmployeeCount with schemabinding as

select c.CompanyID, cEC.EmployeeCount
  from dbo.Company c
  left
  join
(select emp.CompanyID, count(1) EmployeeCount
  from dbo.Employee emp
 group by emp.CompanyID) cEC

   on c.CompanyID = cEC.CompanyID;

для всех строк. В Триггере я хоть только для нжуных сделаю.
Но это уже не вопрос. Сосредоточимся на конкретных моих двух вопросах.

Тем более тут задачу можно решить и процедурой с подзапросом и обычной вьюхой и т. п.... вот что бы выбрать оптимальный метод надо сначала его реализовать. Я бы всё равно писал триггер, если бы была возможность использовать мат. вьюху, только для того что бы сравнить.
5 янв 10, 18:57    [8150252]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
NIIIK
Member

Откуда: Россия, Ростовская область, г. Таганрог
Сообщений: 1295
aleks2,

Ещё раз спасибо за материализованное представление, предложенное в уважительной форме, но .... без него рально обойтись прийдётся. Разве что можно создать таблицу, которую опять же триггером обновлять. Я не зря спросил про триггеры )
5 янв 10, 19:00    [8150261]     Ответить | Цитировать Сообщить модератору
 Re: триггер, отлов события.  [new]
aleks2
Guest
NIIIK
aleks2,

Ещё раз спасибо за материализованное представление, предложенное в уважительной форме, но .... без него рально обойтись прийдётся. Разве что можно создать таблицу, которую опять же триггером обновлять. Я не зря спросил про триггеры )


-- Даже если от триггера не спрятаться - не скрыться...
-- Это ишо не повод пИсать быдлокод

update T set [count]=[count]+y.[count]
FROM 
aTable T
INNER JOIN
(select CompanyID, SUM([count]) [count]
	FROM
	(
	 select CompanyID, -count(employeeID) [count] FROM DELETED GROUP BY CompanyID
	 UNION ALL
	 select CompanyID, count(employeeID) [count] FROM INSERTED GROUP BY CompanyID
	) x
 group by CompanyID
) y
ON T.CompanyID=y.CompanyID
WHERE y.[count]<>0
6 янв 10, 08:40    [8151284]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить