SQL COM C?LCULO

LUIS.HERRERA 11/12/2014 11:30:43
#443134
Bom dia!
Estou montando um novo módulo que conterá algumas tabelas relacionada. A estrutura é bastante complexa, mas abaixo está simplificado só para eu tentar fazer o cálculo necessário.
Os registros principais terão de pegar um só valor da tabela relacionada para cada campo e somar, se o valor < tabValorCorte.Pontos, então SIG = false, se o valor >= abValorCorte.Pontos então SIG = true.

A estrutura é:

tabValorCorte
ID, IDEmpresa, Pontos (todos tipo inteiros)

tabRegistros
ID, IDEmpresa, Descricao, IDItemGrupo1, IDItemGrupo2, IDIemGrupo3, IDItemGrupo4 (Os campos ID são todos Inteiros). Aqui na verdade são 10 campos IDItemGrupo de 1 a 10, sendo que se o valor do campo for 0 (zero) siginifica que não há registro associado a ela na tabItensGrupo. Isso porque no cadastro é possível definir de 1 a 10 grupos, e se não existir alguns grupos, esse campo recebe o valor zero para não fazer parte do cálculo.

tabItensGrupo
IDItem, Descricao, Pontos (ID e Pontos são tipo inteiro)

Problema:
Como os pontos de tabItensGrupo pode ser alterado, bem como o ValorCorte, não posso gravar esses valores na tabela Registros só os IDs de relacionamento. Assim tenho de fazer o cálculo no momento da consulta. Essa consulta será no formulário (edição dos registro) e gerar relatório.
1- No formulário de edição, como eu poderia listar todos os registros cujo campo SIG fosse true ou false, se esse campo não existe fisicamente na tabela e seu resultado é fruto do cálculo citado acima?

2- A consulta também pode ser na listagem do relatório, nesse caso ocorre o mesmo problema acima.


Pensei algo assim, mas não sei o calculo para gerar o SIG corretamente

SELECT REG.ID, REG.IDEmpresa, REG.Descricao, REG.IDItemGrupo1, ITEM1.Descricao, ITEM1.Pontos, REG.IDItemGrupo2, ITEM2.Descricao, ITEM2.Pontos, REG.IDItemGrupo3, ITEM3.Descricao, ITEM3.Pontos, REG.IDItemGrupo4, ITEM4.Descricao,  ITEM4.Pontos, FROM tabRegistros as REG LEFT OUTER JOIN tabItensGrupo  AS ITEM1 ON REG.IDItensGrupo1 = ITEM1.IDITEM LEFT OUTER JOIN tabItensGrupo  AS ITEM2 ON REG.IDItensGrupo2 = ITEM2.IDITEM LEFT OUTER JOIN tabItensGrupo  AS ITEM3 ON REG.IDItensGrupo3 = ITEM3.IDITEM LEFT OUTER JOIN tabItensGrupo  AS ITEM4 ON REG.IDItensGrupo4 = ITEM4.IDITEM WHERE ((REG.IDEmpresa)=@IDEmpresa) ORDER BY REG.Descricao ASC;


Nota: No sistema antigo que tenho, esse módulo tinha o camo SIG na tabRegistros, mas se o valor de algum Item de grupo fosse alterado, este campo não teria como ser atualizado, o que certamente acarretaria erro de status. Estou agora tentando fazer o cálculo na hora da pesquisa, e isso que estou com dificuldade.

Alguém saberia como fazer esse SQL? Uso SQL Server 2008 R2 Express
TUNUSAT 11/12/2014 13:42:17
#443142
LUIS HERRERA,

P: 1- No formulário de edição, como eu poderia listar todos os registros cujo campo SIG fosse true ou false, se esse campo não existe fisicamente na tabela e seu resultado é fruto do cálculo citado acima?

R:
Bom ... você pode declarar uma variável ou uma tabela e atribuir um valor a ela. No caso uma variável boolean (BIT que pode ser [ô]0[ô] ou [ô]1[ô]).

Exemplo de BIT:
==================================
DECLARE @teste bit;
SET @teste = 0;
select @teste
==================================

Veja mais em:
==================================
DECLARE @local_variable (Transact-SQL)
http://msdn.microsoft.com/pt-br/library/ms188927.aspx
==================================

P: 2- A consulta também pode ser na listagem do relatório, nesse caso ocorre o mesmo problema acima.
R: A consulta pode chamar uma Stored Procedure?


... Outro assunto ...
... é legal usar estas ferramentas online para formatar seu código SQL (fica visualmente melhor):

http://sqlformat.org/
http://www.sql-format.com/


SELECT REG.ID,
REG.IDEmpresa,
REG.Descricao,
REG.IDItemGrupo1,
ITEM1.Descricao,
ITEM1.Pontos,
REG.IDItemGrupo2,
ITEM2.Descricao,
ITEM2.Pontos,
REG.IDItemGrupo3,
ITEM3.Descricao,
ITEM3.Pontos,
REG.IDItemGrupo4,
ITEM4.Descricao,
ITEM4.Pontos,
FROM tabRegistros AS REG
LEFT OUTER JOIN tabItensGrupo AS ITEM1 ON REG.IDItensGrupo1 = ITEM1.IDITEM
LEFT OUTER JOIN tabItensGrupo AS ITEM2 ON REG.IDItensGrupo2 = ITEM2.IDITEM
LEFT OUTER JOIN tabItensGrupo AS ITEM3 ON REG.IDItensGrupo3 = ITEM3.IDITEM
LEFT OUTER JOIN tabItensGrupo AS ITEM4 ON REG.IDItensGrupo4 = ITEM4.IDITEM
WHERE ((REG.IDEmpresa)=@IDEmpresa)
ORDER BY REG.Descricao ASC;


[][ô]s,
Tunusat.
LUIS.HERRERA 11/12/2014 14:05:55
#443145
Desculpe mas não entendi.
1) Essa declaração de variável eu faria onde? Pelo que entendi ela conteria o resultado do cálculo para cada tagRegistro encontrado, true ou false em relação a soma de cada um dos campos ItemGrupo1, 2, 3, etc...
Onde ela seria declarada e como eu atribuiria a ela o resultado do cálculo (não demonstrado) e como eu a incluiria como uma coluna para o resultado do SELECT acima?

2) No SELECT que passei só tem o esqueleto dos campos, não sem a forma de calcular a soma dos campos, nem como saber se seu conteúdo é maior que zero, pois se for zero não terá correlação com o item de tabItemGrupo?
Nota: Infelizmente não gostaria de incluir StoreProcedure visto que o sistema rodará em vários clientes e não terei acesso aos bancos de dados deste. é um sistema corporativo para n empresas, assim prefiro que tudo fique no EXE para fácil manutenção e atualização.

3) Obrigado pelos links de formatação, não conhecia este recurso.
FFCOUTO 11/12/2014 15:00:29
#443150
Você deve somar os pontos de cada grupo e comparar usando o CASE. Dê um alias para o CASE, veja o exemplo abaixo.
Depois bastar usar normalmente o campo, assim: dr[[Ô]resultado[Ô]]

SELECT REG.ID,
CASE WHEN (ITEM1.Pontos + ITEM2.Pontos + ITEM3.Pontos + ITEM4.Pontos) < tabValorCorte.Pontos THEN 0
ELSE 1
END CASE AS resultado
FROM tabRegistros AS REG
LEFT OUTER JOIN tabItensGrupo AS ITEM1 ON REG.IDItensGrupo1 = ITEM1.IDITEM
LEFT OUTER JOIN tabItensGrupo AS ITEM2 ON REG.IDItensGrupo2 = ITEM2.IDITEM
LEFT OUTER JOIN tabItensGrupo AS ITEM3 ON REG.IDItensGrupo3 = ITEM3.IDITEM
LEFT OUTER JOIN tabItensGrupo AS ITEM4 ON REG.IDItensGrupo4 = ITEM4.IDITEM
WHERE ((REG.IDEmpresa)=@IDEmpresa)
ORDER BY REG.Descricao ASC;


No tabValorCorte.Pontos você pode usar uma subquery ou utilizar um parâmetro ao executar o comando ou, ainda, se a sua tabela tabValorCorte tiver alguma campo que possa ser relacionado a tabela tabRegistros.

Qualquer dúvida faça contato
LUIS.HERRERA 11/12/2014 15:56:34
#443151
Grande amigo Fabiano, sempre quebrando meus galhos.
Ainda não tenho os dados na tabela e estou fazendo a tela de cadastro, então testei sem dados. Tive de fazer só um ajuste no case, pois a sintaxe não funcionava, e [Ô]Rodou[Ô].
Segunda termino o cadastro e incluo alguns registro pra testar e dou o retorno.

Nota: Sim a tabela de valorcorte tem um campo relacionável IDEmpresa, assim fica fácil.

o código do Case no SQL 2008 é assim:

campo = CASE WHEN (ITEM1.Pontos + ITEM2.Pontos + ITEM3.Pontos + ITEM4.Pontos) < tabValorCorte.Pontos THEN 0
ELSE 1
END

Obrigadão por enquanto e Ótimo final de semana para todos.
FILMAN 11/12/2014 22:48:41
#443159
Veja se ajuda minha ideia

Primeiro mudaria a estrutura de tabela, ficaria assim:

CREATE TABLE tabValorCorte (
ID INT,
IDEmpresa INT,
Pontos INT
);

CREATE TABLE tabRegistros (
ID INT,
IDEmpresa INT,
Descricao VARCHAR(50)
);

CREATE TABLE tabRegistrosGrupos (
IDRegistro INT,
IDEmpresa INT,
IDItemGrupo INT
);

CREATE TABLE tabItensGrupo (
IDItem INT,
Descricao VARCHAR(50),
Pontos INT
);


Os grupos ficariam fora da tabela de Registro, em uma tabela chamada tabRegistrosGrupos, portanto podendo ter mais de 10 e não poluindo a tabela. A quantidade pode ser limitada via aplicação.

E o SQL ficaria assim:

SELECT 
A.RE_ID,
A.RE_DESCRICAO,
A.REG_IDITEMGRUPO,
A.IG_DESCRICAO,
A.IG_PONTOS,
CASE
WHEN A.IG_PONTOS < VC.Pontos THEN [ô]FALSO[ô]
ELSE [ô]VERDADEIRO[ô]
END AS SIG
FROM (
SELECT
RE.ID AS RE_ID,
RE.IDEmpresa AS RE_IDEMPRESA,
RE.Descricao AS RE_DESCRICAO,
REG.IDItemGrupo AS REG_IDITEMGRUPO,
IG.Descricao AS IG_DESCRICAO,
COALESCE(SUM(IG.Pontos),0) AS IG_PONTOS
FROM tabRegistros RE
LEFT JOIN tabRegistrosGrupos REG ON (REG.IDRegistro = RE.ID AND REG.IDEmpresa = RE.IDEmpresa)
LEFT JOIN tabItensGrupo IG ON (IG.IDItem = REG.IDItemGrupo)
WHERE RE.IDEmpresa = @IDEmpresa
GROUP BY RE.ID,RE.IDEmpresa,RE.Descricao,REG.IDItemGrupo,IG.Descricao
) A
INNER JOIN tabValorCorte VC ON (VC.IDEmpresa = A.RE_IDEMPRESA)
ORDER BY A.RE_DESCRICAO


Não realizei testes, mas creio que vai funcionar
Tópico encerrado , respostas não são mais permitidas