Pergunta

Eu estou tendo uma consulta SQL (MSSQLSERVER) onde eu adicionar colunas para o conjunto de resultados usando subselects:

SELECT P.name, 
(select count(*) from cars C where C.type = 'sports') AS sportscars,
(select count(*) from cars C where C.type = 'family') AS familycars,
(select count(*) from cars C where C.type = 'business') AS businesscars
FROM people P
WHERE P.id = 1;

A consulta acima é apenas a partir de uma configuração de teste que é um pouco absurdo, mas serve muito bem como exemplo, eu acho. A consulta Na verdade, estou trabalhando em vãos uma série de tabelas complexas que apenas desvia o assunto em questão.

No exemplo acima, cada registro na tabela "pessoas" também tem três colunas adicionais: "wantsSportscar", "wantsFamilycar" e "wantsBusinesscar". Agora o que eu quero fazer é só fazem o subselect de cada coluna adicional se o respectivo "quer ....." campo na tabela de pessoas é definido como "true". Em outras palavras, eu só quero fazer o primeiro subselect se P.wantsSportscar é definido como verdadeiro para aquela pessoa específica. Os segundo e terceiro subselects deve funcionar de forma semelhante.

Assim, a maneira esta consulta deve funcionar é que ele mostra o nome de uma pessoa específica e o número de modelos disponíveis para os tipos de carros que ele quer possuir. Talvez valha a pena notar que o meu conjunto de resultados final será sempre contêm apenas um único registro, ou seja, a de um usuário específico.

É importante que se uma pessoa não está interessado em um certo tipo de carros, que a coluna para esse tipo não serão incluídas no conjunto de resultados final. Um exemplo para ter certeza que esta é clara:

Se a pessoa A quer um carro esporte e um familycar, o resultado seria incluir as colunas "nome", "sportscars" e "familycars".

Se a pessoa B quer um BusinessCar, o resultado seria incluir as colunas "nome" e "BusinessCar".

Eu tenho tentado usar várias combinações com IF, CASE e EXISTE declarações, mas até agora eu não fui capaz de obter uma solução sintaticamente correto. Alguém sabe se isso é mesmo possível? Note-se que a consulta irá ser armazenado em um procedimento armazenado.

Foi útil?

Solução

No seu caso, existem layouts de coluna 8 possível e para fazer isso, você vai precisar 8 consultas separadas (ou construir sua consulta dinamicamente).

Não é possível alterar o layout de resultados dentro de uma única consulta.

Em vez disso, você pode projetar sua consulta a seguinte:

SELECT  P.name, 
        CASE WHEN wantssport = 1 THEN (select count(*) from cars C where C.type = 'sports') ELSE NULL END AS sportscars,
        CASE WHEN wantsfamily = 1 THEN (select count(*) from cars C where C.type = 'family') ELSE NULL END AS familycars,
        CASE WHEN wantsbusiness = 1 THEN (select count(*) from cars C where C.type = 'business') ELSE NULL END AS businesscars
FROM    people P
WHERE   P.id = 1

que irá selecionar NULL na coluna apropriada, se uma pessoa não quer, e analisar estes NULL de no lado do cliente.

Note que o modelo relacional responde às consultas em termos de relations.

No seu caso, a relação é a seguinte:. "Esta pessoa necessidades são satisifed com isso muitos carros esporte, isso muitas carros negócio e isso muitos carros familiares"

O modelo relacional sempre responde a esta pergunta específica com uma relação quaternário.

Ele não omitir qualquer um dos membros de relação: em vez disso, ele só define-los para NULL que é a maneira do SQL para mostrar que o membro de uma relação não está definido, aplicável ou significativo

.

Outras dicas

Eu sou mais um cara Oracle, mas há uma grande chance do mesmo se aplica. A menos que eu tenha entendido mal, o que você quer não é possível nesse nível - você sempre terá um número estático de colunas. Sua consulta pode controlar se a coluna está vazia, mas uma vez na parte mais externa da consulta que você tenha especificado um número X de colunas, você está garantido para obter X colunas em seu conjunto de resultados.

Como eu disse, eu estou familiarizado com o MS SQL Server, mas eu estou supondo que haverá alguma maneira de executar SQL dinâmico, caso em que você deve pesquisar que desde que deverá permitir-lhe criar uma consulta mais flexível.

Você pode ser capaz de fazer o que quiser, seleccionando primeiro a valores como linhas separadas em uma tabela temporária, em seguida, fazendo um pivô na mesa (virando as linhas em colunas).

É importante que se uma pessoa não é interessado em um determinado tipo de carros, que a coluna para esse tipo não irá ser incluído no conjunto de resultados finais. A exemplo, para ter certeza que esta é clara:

Você não será capaz de fazê-lo em SQL simples. Eu sugiro que você acabou de fazer esta NULL coluna ou ZERO.

Se você quiser que a consulta seja expandir dinamicamente quando os carros novos são adicionados, então articulados poderia ajudá-lo um pouco.

Existem três fundamentos que você quer aprender a fazer este trabalho fácil. O primeiro é a normalização dos dados, o segundo é GROUP BY, e o terceiro é PIVOT.

Em primeiro lugar, a normalização de dados. Seu projeto da tabela de pessoas não está na primeira forma normal. As colunas "wantsports", "wantfamily", "wantbusiness" são realmente um grupo de repetição, embora eles não podem olhar como um. Se você pode modificar o design da tabela, você vai achar que é vantajoso para criar uma terceira tabela, vamos chamá-lo "peoplewant", com duas colunas principais, personid e CarType. Eu posso entrar em detalhes sobre por que este projeto será mais flexível e poderosa, se quiser, mas eu vou pular isso por enquanto.

Ligado para GROUP BY. Isso permite que você produzir um resultado que resume cada grupo em uma linha do resultado.

SELECT 
    p.name, 
    c.type, 
    c.count(*) as carcount
FROM people p, 
   INNER JOIN peoplewant pw ON p.id = pw.personid 
   INNER JOIN cars c on pw.cartype = c.type
WHERE
   p.id = 1
GROUP BY 
   p.name,
   c.type

Esta consulta (não testado) lhe dá o resultado desejado, a não ser que o resultado tem uma linha separada para cada tipo de carro que a pessoa quer.

Finalmente, PIVOT. A ferramenta PIVOT em seu DBMS permite transformar este resultado em uma forma onde há apenas uma linha para a pessoa, e não há uma coluna separada para cada um dos cartypes procurados por essa pessoa. Eu não usei PIVOT mim, então eu vou deixar alguém editar esta resposta para fornecer um exemplo usando PIVOT.

Se você usar a mesma técnica para recuperar dados para várias pessoas em uma varredura, tenha em mente que uma coluna será exibido para cada tipo queria que qualquer pessoa quer, e zeros irá aparecer no resultado PIVOT para pessoas que não querem um tipo de carro que está nas colunas de resultados.

Apenas me deparei com este post através de uma pesquisa no google, então eu percebo que eu estou atrasado para esta festa por um pouco, mas .. certo de que este é realmente possível para fazer ... no entanto, I não sugeriria realmente fazê-lo desta maneira, porque é geralmente considerado um Very Bad Thing (tm).

SQL dinâmico é sua resposta.

Antes de dizer como fazê-lo, quero prefaciar este com, Dynamic SQL é uma coisa muito perigosa, se você não está saneantes sua entrada a partir da aplicação.

Assim, portanto, proceder com cautela:

declare @sqlToExecute nvarchar(max);
declare @includeSportsCars bit;
declare @includeFamilyCars bit;
declare @includeBusinessCars bit;

set @includeBusinessCars = 1
set @includeFamilyCars = 1
set @includeSportsCars  = 1

set @sqlToExecute = 'SELECT P.name '

if @includeSportsCars = 1 
    set @sqlToExecute = @sqlToExecute + '(select count(*) from cars C where C.type = ''sports'') AS sportscars, ';
if @includeFamilyCars = 1
    set @sqlToExecute = @sqlToExecute + '(select count(*) from cars C where C.type = ''family'') AS familycars, ';
if @includeBusinessCars = 1
    set @sqlToExecute = @sqlToExecute + '(select count(*) from cars C where C.type = ''business'') AS businesscars '

set @sqlToExecute = @sqlToExecute + ' FROM people P WHERE P.id = 1;';

exec(@sqlToExecute)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top