Eu tenho duas tabelas CustomerProfile e NewData. O CustomerProfile tem CustomerId,ProfileId,startDate e endDate. A tabela NewData é um novo dado que está chegando apenas com o ProfileId. Crio uma tabela temporária com ids de ambas as tabelas denominadas #groupedProfileIds. Em seguida, faço um loop na tabela temporária, verificando se o id está em alguma da tabela principal. Então base a contagem que eu faço um insert ou update. Eu tentei fazer isso com while e verificando a contagem de ambas as tabelas, mas queria ver se existe uma maneira melhor.
O objetivo disso é ter uma base de tabela CustomerProfile atualizada na tabela newData. Se o id não estiver na tabela newData, a tabela CustomerProfile será atualizada com uma data de término. Se forem novos Id serão inseridos com uma data de início. Eu uso ' @OldProfileId = 1 e @NewProfileId = 0' para fazer a atualização porque os dados não estão na nova tabela. Para a inserção eu faço ' @OldProfileId = 0 e @NewProfileId = 1' porque os dados estão apenas no newData. Eu não preciso marcar 1 porque eles estariam nas duas tabelas.
http://sqlfiddle.com/#!18/73845
select * INTO #groupedProfileIds from(
SELECT ProfileId FROM CustomerProfile
UNION
SELECT ProfileId FROM NewData) as #tmp
declare @Rowcount int
select @Rowcount=count(*) from #groupedProfileIds
while( @Rowcount>0)
begin
select @Rowcount=@Rowcount-1;
DECLARE @ProfileIds int
set @ProfileIds = (SELECT Id FROM #groupedProfileIds order by Id desc OFFSET @Rowcount ROWS FETCH NEXT 1 ROWS ONLY);
print @ProfileIds
DECLARE @OldProfileId INT
SET @OldProfileId = (SELECT Count(ProfileId) FROM CustomerProfile where ProfileId = @ProfileIds)
DECLARE @NewProfileId INT
SET @NewProfileId = (SELECT Count(ProfileId) FROM #NewData where ProfileId = @ProfileIds)
IF @OldProfileId = 1 and @NewProfileId = 0
BEGIN
update DBO.CustomerProfile set endDate = GETDATE() where ProfileId = @ProfileIds
end
IF @OldProfileId = 0 and @NewProfileId = 1
BEGIN
INSERT INTO DBO. CustomerProfile (CustomerId, ProfileId,startDate)
VALUES (CustomerId,@ProfileIds,GETDATE())
end
Não tenho certeza se entendi sua pergunta da maneira correta, mas se o que entendi foi verdade, a consulta abaixo compara ProfileId de duas tabelas e atualiza o campo endDate com a data atual, ele também insere profileIds da tabela newdata que não existem em CustomerProfile (o campo customerId não está disponível para eles) e preenche o campo StartDate com a data atual:
A melhor maneira de fazer isso é criar uma consulta que tenha os dados desejados. Então você pode decidir o que inserir e o que atualizar.
Se o id do perfil não estiver em CustomerProfile, você deseja inserir uma nova linha com um customerId, não diga de onde você obtém esse customerId, pois tudo o que você tem é um profileId?
A deficiência pela qual você especifica seu requisito é a razão pela qual você não encontra uma solução. E ninguém pode ajudá-lo porque você não diz o que quer. De repente, inserir "câncer" em algum lugar torna tudo muito pior!
Ninguém pode responder sua pergunta porque você não diz o que quer. No entanto, se fizermos algumas suposições, o melhor que fazemos é traçar uma direção que você pode seguir.
Podemos adivinhar alguma coisa do seu esquema de tabela incompleto?
A forma como está escrito deve haver uma tabela Customer e uma tabela Profile
então suas tabelas que você mencionou devem ser preenchidas como:
Eu primeiro retive sua não-restrição customerId NULL para me dar uma saída para não ter que me preocupar em como inferir o customerId de um mero profileId ao inserir. Mas então eu imaginei que poderia completar seu esquema, para tê-lo lógico. Isso cria tarefas adicionais para inserir uma nova linha de cliente e perfil, eu sei como posso fazer isso, mas você não pediu, então não vou fazer isso.
Então, o acima é apenas para eu entender o que você quer. Você ainda não disse o suficiente.
Presumo de sua tabela que seu relacionamento entre Cliente e Perfil é de muitos para muitos. E eu duvido disso. Acho que você realmente não pensou em sua lógica de dados de negócios. Mas para o que estou propondo não importa.
Também não estou interessado em coisas do SQL Server, mas usarei o SQL padrão (meu banco de dados é o PostgreSQL). Se você não pensa em SQL (a linguagem, não o seu software), você não será um bom designer/programador/administrador de banco de dados, como quer que você se chame.
No SQL padrão, "datetime" é chamado de "timestamp" e a maneira padrão de obter o timestamp atual é current_timestamp.
Sobre sua data final, você diz:
Então, ao inserir em sua tabela, presumo que startDate = current_timestamp e endDate = NULL.
Finalmente, eu assumo que esses ids são "sequências", mas vou me abster de qualquer extensão de sequência para qualquer banco de dados e apenas determinar o próximo valor de
SELECT max(fooId) + 1 FROM Foo
onde "Foo" pode ser Cliente, Perfil ou Perfil do Cliente.
Com todas essas suposições feitas, começo, como disse, do jeito que você deve sempre começar. Escreva um SELECT que lhe dará a tabela final desejada, ou, aqui, começo com a parte INSERT:
Agora a ATUALIZAÇÃO. Você parece esperar que todos os profileIds que ainda não terminaram apareçam em seu NewData todas as vezes. Inicialmente, entendi que você estenderia o endDate toda vez que encontrar o profileId no NewData. Isso me faz pensar o que acontece se um profileId reaparecer de repente no NewData depois que você já o perdeu uma vez e já adicionou um endDate? Você deveria apagar o endDate com NULL novamente? Você não pediu por isso, então eu não vou fazer isso. Mas você não pensou em seu design se não considerar isso.
Aqui está a partição da sua tabela que você atualiza, após a atualização:
Então aqui eu realmente redefiniria seu endDate para NULL se o profileId reaparecer. Mas a atualização de qualquer maneira fica muito simples:
Você executa a parte UPDATE primeiro, depois o INSERT. E você está feito.
A melhor descrição do seu requisito é uma consulta SELECT que fará o que você deseja. O que você INSERT vs. UPDATE é apenas uma questão secundária. Isso é ainda mais verdadeiro se você também tiver que inserir linhas Cliente e Perfil para atender às restrições de chave estrangeira. No PostgreSQL eu faço essas coisas em uma única consulta. Em bancos de dados menores, como Oracle ou MS SQL Server, acho que você precisa executar várias etapas em uma transação.