Форум программистов, компьютерный форум, киберфорум
Microsoft SQL Server
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.53/19: Рейтинг темы: голосов - 19, средняя оценка - 4.53
471 / 234 / 73
Регистрация: 25.05.2012
Сообщений: 1,054
Записей в блоге: 1
1

Вычисляемое поле одной таблицы по количеству записей в другой: триггер?

18.07.2013, 18:26. Показов 3985. Ответов 12
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день!
Вопрос начинающего: необходимо, чтобы поле Tours.Capacity автоматически вычислялось по количеству записей в Tourists-Tours соответствующего TourID (см. вложение). Пока что решил задачу в лоб триггерами AFTER INSERT, AFTER DELETE:

SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TRIGGER [dbo].[Tourists-Tours_tri] ON [dbo].[Tourists-Tours]
WITH EXECUTE AS CALLER
FOR INSERT, UPDATE
AS
BEGIN
  /* Trigger body */
  DECLARE @a AS INTEGER;
  DECLARE @b AS INTEGER;
  SET @b = (SELECT TourID FROM inserted);
  SET @a = (SELECT COUNT (TourID) FROM [dbo].[Tourists-Tours] WHERE TourID = @b);
 
  UPDATE Tours SET Capacity = @a WHERE TourID = @b; 
END
Может есть более изящное/правильно решение?

Или я пытаюсь изобрести велосипед и достаточно будет обойтись JOIN для вывода количества?
Миниатюры
Вычисляемое поле одной таблицы по количеству записей в другой: триггер?  
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
18.07.2013, 18:26
Ответы с готовыми решениями:

Посчитать количество записей в одной таблице и передать значение в поле другой таблицы
Здравствуйте. Есть две таблицы "Деканат" и "Студенты". Нужно чтобы в поле "Деканат.Количество...

Вычисляемое поле с данными из другой таблицы
есть 2 таблицы: сотрудники (код сотрудника, оклад) и начисления зарплаты (код начисления, код...

Вычисляемое поле на форме (данные из другой таблицы)
Доброго времени суток, уважаемые форумчане. В MS Access, как и в VBA, слегка плаваю. Есть 2...

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

12
1116 / 761 / 183
Регистрация: 27.11.2009
Сообщений: 2,269
18.07.2013, 20:08 2
Можно в [dbo].[Tourists-Tours] одним INSERTом вставить 2 записи?
0
3499 / 2083 / 742
Регистрация: 02.06.2013
Сообщений: 5,078
18.07.2013, 22:54 3
Индексированное представление позволит обойтись без тиггера(ов). Тем более, что он неправильный.
1.
T-SQL
1
alter table Tours drop column Capacity
2.
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
create view vTourCapacity
with schemabinding
as
select
 TourID,
 count_big(*) as Capacity
from
 dbo.[Tourists-Tours]
group by
 TourID;
go
 
create unique clustered index IX_vTourCapacity__TourID on dbo.vTourCapacity (TourID);
1
471 / 234 / 73
Регистрация: 25.05.2012
Сообщений: 1,054
Записей в блоге: 1
19.07.2013, 10:09  [ТС] 4
Цитата Сообщение от iap Посмотреть сообщение
Можно в [dbo].[Tourists-Tours] одним INSERTом вставить 2 записи?
Нет, один INSERT - одна запись.
Но это искусственное ограничение в силу моих недостаточных знаний в этой области. Если можно будет обойтись без триггеров или реализовать обработку вставки нескольких записей, то конечно же его не будет.

Добавлено через 11 минут
Цитата Сообщение от invm Посмотреть сообщение
Индексированное представление позволит обойтись без тиггера(ов). Тем более, что он неправильный.
1.
T-SQL
1
alter table Tours drop column Capacity
2.
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
create view vTourCapacity
with schemabinding
as
select
 TourID,
 count_big(*) as Capacity
from
 dbo.[Tourists-Tours]
group by
 TourID;
go
 
create unique clustered index IX_vTourCapacity__TourID on dbo.vTourCapacity (TourID);
Спасибо, работает как требовалось
0
1116 / 761 / 183
Регистрация: 27.11.2009
Сообщений: 2,269
19.07.2013, 10:18 5
Цитата Сообщение от NewOrdered Посмотреть сообщение
Нет, один INSERT - одна запись.
Но это искусственное ограничение в силу моих недостаточных знаний в этой области. Если можно будет обойтись без триггеров или реализовать обработку вставки нескольких записей, то конечно же его не будет.)
Где это ограничение??
Кто помешает мне выполнить INSERT двух записей?
Вы проверяете на входе в триггер, что записей не больше одной? Нет!
Типичный пример говнокода, который работает только в очень специальных случаях
и с грохотом падает при малейшем отклонении от них.
1
471 / 234 / 73
Регистрация: 25.05.2012
Сообщений: 1,054
Записей в блоге: 1
19.07.2013, 11:35  [ТС] 6
Цитата Сообщение от iap Посмотреть сообщение
Где это ограничение??
Кто помешает мне выполнить INSERT двух записей?
Вы проверяете на входе в триггер, что записей не больше одной? Нет!
Типичный пример говнокода, который работает только в очень специальных случаях
и с грохотом падает при малейшем отклонении от них.
Вам - никто. А пользователю, работающему с формой, которая добавляет записи, - я как разработчик этой формы. И если потребуется, то будут реализованы проверки/ограничения на стороне сервера.
И почему вы решили, что это будет окончательный вариант решения задачи?
Пока что это только дискуссия.

Добавлено через 8 минут
iap, Возможно, это действительно неправильный подход - создавать код для "специальных случаев". Но я для того и здесь, чтобы понять, где я ошибаюсь.
0
1116 / 761 / 183
Регистрация: 27.11.2009
Сообщений: 2,269
19.07.2013, 11:41 7
Цитата Сообщение от NewOrdered Посмотреть сообщение
iap, Возможно, это действительно неправильный подход - создавать код для "специальных случаев". Но я для того и здесь, чтобы понять, где я ошибаюсь.
Дык, я и показываю, где.
Может, не всё показываю, но я же не один на форуме?

В общем, форма какая-то тут совершенно не при чём.
Клиент-серверная технология - это в общем случае один сервер и сколько угодно клиентов,
которые должны посылать серверу корректные запросы, а он их должен корректно обработать.
Ваш клиент вставляет по одной строке, а другой вставляет сразу миллион!
И это нормальная ситуация.
0
471 / 234 / 73
Регистрация: 25.05.2012
Сообщений: 1,054
Записей в блоге: 1
19.07.2013, 13:09  [ТС] 8
Цитата Сообщение от iap Посмотреть сообщение
Дык, я и показываю, где.
Может, не всё показываю, но я же не один на форуме?

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

Добавлено через 1 час 7 минут
Цитата Сообщение от invm Посмотреть сообщение
Индексированное представление позволит обойтись без тиггера(ов). Тем более, что он неправильный.
1.
T-SQL
1
alter table Tours drop column Capacity
2.
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
create view vTourCapacity
with schemabinding
as
select
 TourID,
 count_big(*) as Capacity
from
 dbo.[Tourists-Tours]
group by
 TourID;
go
 
create unique clustered index IX_vTourCapacity__TourID on dbo.vTourCapacity (TourID);

Правильно ли будет делать вывод Capacity вот так:

T-SQL
1
2
3
4
5
6
7
8
9
10
SELECT 
T.TourID as 'N', 
TL.Name as 'Наименование', 
T.DateStart as 'Дата отъезда', 
T.DateEnd as 'Дата приезда', 
TC.Capacity as 'Кол-во туристов',
T.Comment as 'Комментарий'
FROM Tours as T 
JOIN TourList as TL ON TL.TourListID = T.TourListID
LEFT JOIN vTourCapacity as TC ON TC.TourID = T.TourID
?
0
3499 / 2083 / 742
Регистрация: 02.06.2013
Сообщений: 5,078
19.07.2013, 15:23 9
Вот так:
T-SQL
1
2
3
...
LEFT JOIN vTourCapacity with (noexpand) as TC ON TC.TourID = T.TourID
...
1
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
19.07.2013, 16:15 10
invm, а почему LEFT JOIN а не INNER JOIN ? Это же scan вместо seek ? А TourID во view присутствуют все, и однократно...
0
3499 / 2083 / 742
Регистрация: 02.06.2013
Сообщений: 5,078
19.07.2013, 16:52 11
Цитата Сообщение от cygapb-007 Посмотреть сообщение
Это же scan вместо seek
Почему вы так решили?
Цитата Сообщение от cygapb-007 Посмотреть сообщение
А TourID во view присутствуют все
В том-то и дело, что не все, а только те для которых есть записи в [Tourists-Tours].
0
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
19.07.2013, 18:28 12
Цитата Сообщение от invm Посмотреть сообщение
Почему вы так решили?
в план заглянул Никогда не пользовался индексированными представлениями - интересно стало))
Кликните здесь для просмотра всего текста
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
create table Tours (TourID int identity primary key, name nvarchar(100))
insert Tours values ('t1'),('t2')
 
create table [Tourists-Tours] (TourID int, TouristID int, primary key(TourID, TouristID))
go
create view vTourCapacity with schemabinding as
select TourID, count_big(*) as Capacity
   from dbo.[Tourists-Tours]
   group by TourID;
go
create unique clustered index IX_vTourCapacity__TourID on dbo.vTourCapacity (TourID);
go
 
insert [Tourists-Tours] values (1,1)
insert [Tourists-Tours] values (1,2),(2,2)
insert [Tourists-Tours] values (1,1)
update [Tourists-Tours] set TouristID=3 where TourID=1 and TouristID=2
delete [Tourists-Tours] where TourID=2 and TouristID=2
 
select * 
from Tours t
join [Tourists-Tours] l on l.TourID=t.TourID
join vTourCapacity v on v.TourID=t.TourID
 
select * 
from Tours t
join [Tourists-Tours] l on l.TourID=t.TourID
join vTourCapacity v with(noexpand) on v.TourID=t.TourID
 
select * 
from Tours t
join [Tourists-Tours] l on l.TourID=t.TourID
left join vTourCapacity v on v.TourID=t.TourID
 
select * 
from Tours t
join [Tourists-Tours] l on l.TourID=t.TourID
left join vTourCapacity v with(noexpand) on v.TourID=t.TourID
 
select * from Tours
select * from [Tourists-Tours]
select * from vTourCapacity
 
drop table Tours
drop view vTourCapacity
drop table [Tourists-Tours]

Цитата Сообщение от invm Посмотреть сообщение
В том-то и дело, что не все, а только те для которых есть записи в [Tourists-Tours].
Да, протормозил...

Добавлено через 48 минут
С другой стороны, ТС указал INNER JOIN TourList, значит и vTourCapacity нужно тоже по INNER JOIN подключать...

Добавлено через 2 минуты
а еще точнее,
T-SQL
1
2
3
4
5
select * 
from Tours t
left join [Tourists-Tours] l 
   join vTourCapacity v with(noexpand) on v.TourID=l.TourID
   on l.TourID=t.TourID
0
3499 / 2083 / 742
Регистрация: 02.06.2013
Сообщений: 5,078
20.07.2013, 16:01 13
Цитата Сообщение от cygapb-007 Посмотреть сообщение
в план заглянул
Ну план разный может быть. При lef join будет merge и 2 scan'а. А вот при inner может быть, в зависимости от кардинальности, либо скан по vTourCapacity и seek по Tours + Nested Loops, либо merge и 2 scan'а.
Но ТС'у-то нужен left...
0
20.07.2013, 16:01
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
20.07.2013, 16:01
Помогаю со студенческими работами здесь

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

Использование двух записей одной таблицы в одной записи другой
Всем привет! Есть таблица "Application", в ней есть 2 поля, которые содержат: ID пользователя,...

Обновить поля одной таблицы - полями другой используя триггер
Привет всем. В общем задача такая - вставить или обновить с помощью триггера 2 поля book_price,...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru