2015-10-05 5 views
1

Я столкнулся с проблемой создания UDF с count distinct в запросе. Я создал таблицу amtest, которые имеют следующий:Count Distinct не работает в UDF в SQL Server 2008

CREATE TABLE [dbo].[amtest](
    [ztime] [datetime] NULL, 
    [zutime] [datetime] NULL, 
    [zid] [int] NOT NULL, 
    [xamacadyr] [int] NOT NULL, 
    [xamreg] [varchar](20) NOT NULL, 
    [xmobile] [varchar](15) NULL, 
    [xamclasssec] [varchar](30) NULL, 
PRIMARY KEY CLUSTERED 
(
    [zid] ASC, 
    [xamacadyr] ASC, 
    [xamreg] ASC 
) 

данных в таблице amtest следующим образом:

zid xamacadyr xamreg  xmobile   xamclasssec 
100000 2013  201508001 01713236075  Section-B 
100000 2014  201508003 01713236072  Section-A 
100000 2015  201508001 01713236071  Section-A 
100000 2015  201508003 01713236073  Section-A 
100000 2015  201508004 01713236074  Section-A 

Теперь я создал определенный пользователь-функцию с параметром xamreg, так что для любого значения xamreg не может быть 2 различных значения в поле xamclasssec. Например, здесь для значение в xamreg не должно быть двух различных значений (раздел A, раздел B), оно должно допускать только Раздел-A или Раздел B. Для этого я создал следующий UDF:

ALTER FUNCTION [dbo].[CheckTest](@xamreg varchar(30)) 
RETURNS int 
AS 
BEGIN 
    DECLARE @retvar int; 
    select @retvar = COUNT(*) from (select xamclasssec from amtest where [email protected] group by xamclasssec) as tbl ; 
    RETURN @retvar 
END 

И я создал ограничение для amtest таблицы, которая выглядит следующим образом:

alter table amtest 
add constraint chkAmtest 
check(dbo.CheckTest(xamreg)<=1) 

Где я допустил ошибку, так как он не работает ?

ответ

0

Прежде всего, ваша функция может быть упрощена:

CREATE FUNCTION [dbo].[CheckTest](@xamreg varchar(30)) 
RETURNS INT 
AS 
BEGIN 
    RETURN (SELECT COUNT(DISTINCT xamclasssec) FROM amtest WHERE xamreg = @xamreg); 
END 
GO 

бегаю запрос с SQL Fiddle, кажется, работает, но только с INSERT:

SqlFiddleDemo

Если я попробуйте установить DISTINCT значений, которые вы получаете:

Оператор INSERT противоречил ограничению CHECK «chkAmtest». Конфликт произошел в базе данных «db_3_5ec42», таблице «dbo.amtest», столбец «xamreg».

Но есть один недостаток с вашим решением, он не будет работать, когда произойдет UPDATE.

SqlFiddleDemo2

INSERT INTO [dbo].[amtest] 
     (zid ,xamacadyr , xamreg ,  xmobile ,  xamclasssec) 
VALUES (100000 , 2013 ,  201508001 , 01713236075 , 'Section-B'), 
     (100000, 2015,  201508001 , 01713236071 , 'Section-B'); 

UPDATE [dbo].[amtest] 
SET xamclasssec = 'Section-A' 
WHERE xmobile = 01713236071; 

SELECT * 
FROM [dbo].[amtest]; 

Использование AFTER TRIGGER вместо:

SqlFiddleDemo3

CREATE TRIGGER trg_amtest 
ON [dbo].[amtest] 
AFTER INSERT, UPDATE 
AS 
    IF EXISTS (SELECT xamreg, COUNT(DISTINCT xamclasssec) 
      FROM amtest 
      GROUP BY xamreg 
      HAVING COUNT(DISTINCT xamclasssec) > 1) 
    ROLLBACK; 
GO 
+0

@ChistiaChowdhury См. Обновленный ответ – lad2025

+0

Yah, boss, этот UDF работает с запросом на вставку, но когда я ** обновляю ** любую запись, он не работает, я не проверял с помощью триггера (ваше альтернативное решение).Но разве UDF невозможно проверить во время обновления записей? –

+0

Как я уже сказал, ваш UDF проверяет данные, но до завершения UPDATE. Так что нет, с UDF это невозможно. AFTER TRIGGER является правильным способом. – lad2025

0

Если я ошибаюсь, дайте мне знать, но это U DF вернется 2. Это то, что вы хотите?

+0

нет, я не хочу этого. это не работает должным образом, поэтому таблица принимает более 1 значения. этот UDF должен принимать только 1 различное значение, он должен принимать только раздел-A или только раздел-B –

+0

, но если вы выполните этот запрос: «выберите COUNT (*) из (выберите xamclasssec из amtest, где xamreg = 201508001 group by xamclasssec) как tbl; " он вернется 2; – abeppler

+0

Да, так как проверка не работает, запрос выполняется, я хочу противостоять этой ситуации. У меня уже есть альтернативное решение. не волнуйся –