PostgreSQL Select join table and a function - postgresql

I got a function in my database, that returns a table. What I'm trying to do is select joining a table and that function.
I saw that it can't be done in the FROM place, but if I put the function in the select it takes too long to execute.
My SQL is:
select
"Grades"."id",
SUPRIMENTO_LOJA("Grades"."id", 30, 1, 1)
from
"Grades"
This takes more than 500s to execute
I tried this too but it returns an error
select
*
from
"Grades",
SUPRIMENTO_LOJA("Grades"."id", 30, 1, 1)
Whats the best way to make this select to work?
EDIT:
The function is this:
CREATE OR REPLACE FUNCTION suprimento_loja(grade_id integer, vendas_dias integer, lojaId integer, embalagem numeric(15, 4))
RETURNS TABLE(qtd integer, maximo integer, ultFornecedor character varying(50),
ultCompra character varying(10), ultVenda character varying(10), classeLoja character varying(1),
vendas integer, sugestao integer, giroLoja numeric(15, 4))
AS $$
DECLARE
qtde1 integer;
vendasdiae1 integer;
maximoe1 integer;
ultvendae1 timestamp;
ultcomprae1 timestamp;
ultforne1 varchar(50);
classee1 varchar(1);
vendase1 integer;
qtde2 integer;
vendasdiae2 integer;
maximoe2 integer;
ultvendae2 timestamp;
ultcomprae2 timestamp;
ultforne2 varchar(50);
vendase2 integer;
qtde3 integer;
vendasdiae3 integer;
maximoe3 integer;
ultvendae3 timestamp;
ultcomprae3 timestamp;
ultforne3 varchar(50);
vendase3 integer;
giroe1 numeric(15, 4);
giroe2 numeric(15, 4);
giroe3 numeric(15, 4);
BEGIN
with vendas as (
select
sum(coalesce("quantidade", 0)) as vendas_periodo,
"inventario_id"
from
"WVItens"
where
"WVItens"."ultimoDownload" between current_timestamp - (select to_interval(vendas_dias))
and current_timestamp and coalesce("status", '') = ''
group by
"inventario_id")
select into qtde1, vendasdiae1, maximoe1, ultvendae1, ultcomprae1, ultforne1, classee1, vendase1, giroe1
cast("quantidadeAtual" as integer),
cast("vendasPorDia" as integer),
cast("maximoEmDias" as integer),
"dataUltimaVenda",
"dataUltimaCompra",
"ultimoFornecedor",
"classe",
cast(vendas_periodo as integer),
coalesce("giro", 0)
from
"Inventarios",
"Lojas",
vendas
where
"Inventarios"."estoque_id" = "Lojas"."estoque1_id" and
coalesce("Inventarios"."status", '') = '' and
"Inventarios"."id" = vendas."inventario_id" and
"Lojas"."id" = lojaId and
"grade_id" = gradeId;
with vendas as (
select
sum(coalesce("quantidade", 0)) as vendas_periodo,
"inventario_id"
from
"WVItens"
where
"WVItens"."ultimoDownload" between current_timestamp - (select to_interval(vendas_dias))
and current_timestamp and coalesce("status", '') = ''
group by
"inventario_id")
select into qtde2, vendasdiae2, maximoe2, ultvendae2, ultcomprae2, ultforne2, vendase2, giroe2
cast("quantidadeAtual" as integer),
cast("vendasPorDia" as integer),
cast("maximoEmDias" as integer),
"dataUltimaVenda",
"dataUltimaCompra",
"ultimoFornecedor",
cast(vendas_periodo as integer),
coalesce("giro", 0)
from
"Inventarios",
"Lojas",
vendas
where
"Inventarios"."estoque_id" = "Lojas"."estoque2_id" and
coalesce("Inventarios"."status", '') = '' and
"Inventarios"."id" = vendas."inventario_id" and
"Lojas"."id" = lojaId and
"grade_id" = gradeId;
with vendas as (
select
sum(coalesce("quantidade", 0)) as vendas_periodo,
"inventario_id"
from
"WVItens"
where
"WVItens"."ultimoDownload" between current_timestamp - (select to_interval(vendas_dias))
and current_timestamp and coalesce("status", '') = ''
group by
"inventario_id")
select into qtde3, vendasdiae3, maximoe3, ultvendae3, ultcomprae3, ultforne3, vendase3, giroe3
cast("quantidadeAtual" as integer),
cast("vendasPorDia" as integer),
cast("maximoEmDias" as integer),
"dataUltimaVenda",
"dataUltimaCompra",
"ultimoFornecedor",
cast(vendas_periodo as integer),
coalesce("giro", 0)
from
"Inventarios",
"Lojas",
vendas
where
"Inventarios"."estoque_id" = "Lojas"."estoque2_id" and
coalesce("Inventarios"."status", '') = '' and
"Inventarios"."id" = vendas."inventario_id" and
"Lojas"."id" = lojaId and
"grade_id" = gradeId;
qtd := 0;
IF (qtde1 is not null) THEN
qtd := qtd + qtde1;
END IF;
IF (qtde2 is not null) THEN
qtd := qtd + qtde2;
END IF;
IF (qtde3 is not null) THEN
qtd := qtd + qtde3;
END IF;
giroLoja = (giroe1 + giroe2 + giroe3) / 3;
maximo := 0;
IF ((maximoe1 is not null) and (vendasdiae1 is not null)) THEN
maximo := maximo + (maximoe1 * vendasdiae1);
END IF;
IF ((maximoe2 is not null) and (vendasdiae2 is not null)) THEN
maximo := maximo + (maximoe2 * vendasdiae2);
END IF;
IF ((maximoe3 is not null) and (vendasdiae3 is not null)) THEN
maximo := maximo + (maximoe3 * vendasdiae3);
END IF;
IF (qtde1 is null) THEN
qtde1 := 0;
END IF;
IF (qtde2 is null) THEN
qtde2 := 0;
END IF;
IF (qtde3 is null) THEN
qtde3 := 0;
END IF;
IF (maximoe1 is null) THEN
maximoe1 := 0;
END IF;
IF (maximoe2 is null) THEN
maximoe2 := 0;
END IF;
IF (maximoe3 is null) THEN
maximoe3 := 0;
END IF;
IF (vendasdiae1 is null) THEN
vendasdiae1 := 0;
END IF;
IF (vendasdiae2 is null) THEN
vendasdiae2 := 0;
END IF;
IF (vendasdiae3 is null) THEN
vendasdiae3 := 0;
END IF;
IF (vendase1 is null) THEN
vendase1 := 0;
END IF;
IF (vendase2 is null) THEN
vendase2 := 0;
END IF;
IF (vendase3 is null) THEN
vendase3 := 0;
END IF;
ultCompra := '';
ultVenda := '';
ultFornecedor := '';
IF (ultcomprae1 is null) THEN
IF (ultcomprae2 is null) THEN
IF (ultcomprae3 is not null) THEN
ultCompra := cast(extract(day from ultcomprae3) || '/' || extract(month from ultcomprae3) || '/' || extract(year from ultcomprae3) as varchar(10));
ultFornecedor := ultforne3;
END IF;
ELSE
IF ((ultcomprae3 is null) or (ultcomprae2 > ultcomprae3)) THEN
ultCompra := cast(extract(day from ultcomprae2) || '/' || extract(month from ultcomprae2) || '/' || extract(year from ultcomprae2) as varchar(10));
ultFornecedor := ultforne2;
ELSE
ultCompra := cast(extract(day from ultcomprae3) || '/' || extract(month from ultcomprae3) || '/' || extract(year from ultcomprae3) as varchar(10));
ultFornecedor := ultforne3;
END IF;
END IF;
ELSE
IF ((ultcomprae2 is null) or (ultcomprae1 > ultcomprae2)) THEN
IF ((ultcomprae3 is null) or (ultcomprae1 > ultcomprae3)) THEN
ultCompra := cast(extract(day from ultcomprae1) || '/' || extract(month from ultcomprae1) || '/' || extract(year from ultcomprae1) as varchar(10));
ultFornecedor := ultforne1;
ELSE
IF (ultcomprae3 is not null) THEN
ultCompra := cast(extract(day from ultcomprae3) || '/' || extract(month from ultcomprae3) || '/' || extract(year from ultcomprae3) as varchar(10));
ultFornecedor := ultforne3;
END IF;
END IF;
ELSE
IF ((ultcomprae3 is null) or (ultcomprae2 > ultcomprae3)) THEN
ultCompra := cast(extract(day from ultcomprae2) || '/' || extract(month from ultcomprae2) || '/' || extract(year from ultcomprae2) as varchar(10));
ultFornecedor := ultforne2;
ELSE
ultCompra := cast(extract(day from ultcomprae3) || '/' || extract(month from ultcomprae3) || '/' || extract(year from ultcomprae3) as varchar(10));
ultFornecedor := ultforne3;
END IF;
END IF;
END IF;
IF (ultvendae1 is null) THEN
IF (ultvendae2 is null) THEN
IF (ultvendae3 is not null) THEN
ultVenda := cast(extract(day from ultvendae3) || '/' || extract(month from ultvendae3) || '/' || extract(year from ultvendae3) as varchar(10));
END IF;
ELSE
IF ((ultvendae3 is null) or (ultvendae2 > ultvendae3)) THEN
ultVenda := cast(extract(day from ultvendae2) || '/' || extract(month from ultvendae2) || '/' || extract(year from ultvendae2) as varchar(10));
ELSE
ultVenda := cast(extract(day from ultvendae3) || '/' || extract(month from ultvendae3) || '/' || extract(year from ultvendae3) as varchar(10));
END IF;
END IF;
ELSE
IF ((ultvendae2 is null) or (ultvendae1 > ultvendae2)) THEN
IF ((ultvendae3 is null) or (ultvendae1 > ultvendae3)) THEN
ultVenda := cast(extract(day from ultvendae1) || '/' || extract(month from ultvendae1) || '/' || extract(year from ultvendae1) as varchar(10));
ELSE
IF (ultvendae3 is not null) THEN
ultVenda := cast(extract(day from ultvendae3) || '/' || extract(month from ultvendae3) || '/' || extract(year from ultvendae3) as varchar(10));
END IF;
END IF;
ELSE
IF ((ultvendae3 is null) or (ultvendae2 > ultvendae3)) THEN
ultVenda := cast(extract(day from ultvendae2) || '/' || extract(month from ultvendae2) || '/' || extract(year from ultvendae2) as varchar(10));
ELSE
ultVenda := cast(extract(day from ultvendae3) || '/' || extract(month from ultvendae3) || '/' || extract(year from ultvendae3) as varchar(10));
END IF;
END IF;
END IF;
vendas = vendase1 + vendase2 + vendase3;
classeLoja := classee1;
IF ((qtde1 + qtde2 + qtde3) > ((maximoe1 * vendasdiae1) + (maximoe2 * vendasdiae2) + (maximoe3 * vendasdiae3))) THEN
sugestao := 0;
ELSE
sugestao := cast(((((maximoe1 * vendasdiae1) + (maximoe2 * vendasdiae2) + (maximoe3 * vendasdiae3)) - (qtde1 + qtde2 + qtde3)) + 0.4) as integer);
END IF;
RETURN NEXT;
END
$$ LANGUAGE plpgsql;
I tried with some query but it got too long, and it isnt even the final query that I need
with suprimento as (
with vendas as (
select
sum(coalesce("quantidade", 0)) as vendas_periodo,
"inventario_id"
from
"WVItens"
where
"WVItens"."ultimoDownload" between current_timestamp - (select to_interval(30))
and current_timestamp and coalesce("status", '') = ''
group by
"inventario_id")
select
"grade_id",
"estoque_id",
sum(cast("quantidadeAtual" as integer)) as "quantidade",
sum(cast("vendasPorDia" as integer)) as "vendasPorDia",
sum(cast("maximoEmDias" as integer)) as "maximoEmDias",
max("dataUltimaVenda") as "ultVenda",
max("dataUltimaCompra") as "ultCompra",
max("ultimoFornecedor") as "ultFornecedor",
sum(cast(vendas_periodo as integer)) as "vendasPeriodo",
max(coalesce("giro", 0)) as "giro"
from
"Inventarios"
left outer join vendas on ("Inventarios"."id" = vendas."inventario_id")
where
coalesce("Inventarios"."status", '') = ''
group by
"grade_id", "estoque_id")
NEW EDIT!!!
I tried to make one query only but it is runing until now (passed 800seconds), the query is:
WITH suprimento_loja as (
WITH suprimento as (
WITH vendas as (
SELECT "inventario_id"
, SUM(coalesce("quantidade", 0)) as vendas_periodo
FROM "WVItens" vwi
WHERE vwi."ultimoDownload" between current_timestamp - (SELECT to_interval(30))
AND current_timestamp
AND coalesce("status", '') = ''
GROUP BY "inventario_id"
)
SELECT
"estoque_id",
"grade_id",
"classe" as classe
, cast("quantidadeAtual" as integer) as qtd
, cast("vendasPorDia" as integer) as vendasDia
, cast("maximoEmDias" as integer) as maximo
, coalesce("dataUltimaVenda", timestamp'01.01.1980') as ultVenda
, "dataUltimaCompra" as ultCompra
, "ultimoFornecedor" as ultForn
, cast(vendas_periodo as integer) as vendas_periodo
, coalesce("giro", 0) as giro
FROM "Inventarios" inv
LEFT OUTER JOIN vendas ve ON inv."id" = ve."inventario_id"
)
select
lo."id" as id,
e1."grade_id" as grade_id,
e1.ultVenda,
case
when e1.ultVenda > coalesce(e2.ultVenda, timestamp'01.01.1980') and e1.ultVenda > coalesce(e3.ultVenda, timestamp'01.01.1980')
then e1.ultVenda
else
case
when coalesce(e2.ultVenda, timestamp'01.01.1980') > coalesce(e3.ultVenda, timestamp'01.01.1980')
then e2.ultVenda
else e3.ultVenda
end
end as ultVenda,
case
when e1.ultCompra > coalesce(e2.ultCompra, timestamp'01.01.1980') and e1.ultCompra > coalesce(e3.ultCompra, timestamp'01.01.1980')
then e1.ultCompra
else
case
when coalesce(e2.ultCompra, timestamp'01.01.1980') > coalesce(e3.ultCompra, timestamp'01.01.1980')
then e2.ultCompra
else e3.ultCompra
end
end as ultCompra,
case
when e1.ultCompra > coalesce(e2.ultCompra, timestamp'01.01.1980') and e1.ultCompra > coalesce(e3.ultCompra, timestamp'01.01.1980')
then e1.ultForn
else
case
when coalesce(e2.ultCompra, timestamp'01.01.1980') > coalesce(e3.ultCompra, timestamp'01.01.1980')
then e2.ultForn
else e3.ultForn
end
end as ultForn,
coalesce(e1.vendas_periodo, 0) + coalesce(e2.vendas_periodo, 0) + coalesce(e3.vendas_periodo, 0) as vendas_periodo,
e1.classe,
(coalesce(e1.maximo, 0) * coalesce(e1.vendasDia, 0)) + (coalesce(e2.maximo, 0) * coalesce(e2.vendasDia, 0)) + (coalesce(e3.maximo, 0) * coalesce(e3.vendasDia, 0)) as maximo,
coalesce(e1.giro, 0) as giro,
coalesce(e1.qtd, 0) + coalesce(e2.qtd, 0) + coalesce(e3.qtd, 0) as qtde,
case
when coalesce(e1.giro, 0) = 0
then 0
else
case
when ((coalesce(e1.qtd, 0) + coalesce(e2.qtd, 0) + coalesce(e3.qtd, 0)) > ((coalesce(e1.maximo, 0) * coalesce(e1.vendasDia, 0)) + (coalesce(e2.maximo, 0) * coalesce(e2.vendasDia, 0)) + (coalesce(e3.maximo, 0) * coalesce(e3.vendasDia, 0))))
then 0
else cast(((((coalesce(e1.maximo, 0) * coalesce(e1.vendasDia, 0)) + (coalesce(e2.maximo, 0) * coalesce(e2.vendasDia, 0)) + (coalesce(e3.maximo, 0) * coalesce(e3.vendasDia, 0)))
- (coalesce(e1.qtd, 0) + coalesce(e2.qtd, 0) + coalesce(e3.qtd, 0))) + 0.4) as integer)
end
end as sugestao
from
"Lojas" lo
LEFT OUTER JOIN suprimento e2 ON e2."estoque_id" = lo."estoque2_id"
LEFT OUTER JOIN suprimento e3 ON e3."estoque_id" = lo."estoque3_id"
JOIN suprimento e1 ON e1."estoque_id" = lo."estoque1_id")
SELECT
gr."id",
sl1.*,
sl2.*,
sl3.*,
sl4.*,
sl5.*,
sl6.*
FROM
"Grades" gr
JOIN suprimento_loja sl1 ON sl1."grade_id" = gr."id"
JOIN suprimento_loja sl2 ON sl2."grade_id" = gr."id"
JOIN suprimento_loja sl3 ON sl3."grade_id" = gr."id"
JOIN suprimento_loja sl4 ON sl4."grade_id" = gr."id"
JOIN suprimento_loja sl5 ON sl5."grade_id" = gr."id"
JOIN suprimento_loja sl6 ON sl6."grade_id" = gr."id"
WHERE
sl1."id" = 1 AND
sl2."id" = 2 AND
sl3."id" = 3 AND
sl4."id" = 4 AND
sl5."id" = 5 AND
sl6."id" = 6
I used aliases and join so you can read easly

I got it working but in other way.
If someone got some similar problem the solution I got is this:
SELECT
gr.id,
max(CASE sl.id WHEN 1 THEN sl.ultVenda ELSE timestamp'01.01.1980' END) AS ultVenda_l1,
max(CASE sl.id WHEN 2 THEN sl.ultVenda ELSE timestamp'01.01.1980' END) AS ultVenda_l2,
max(CASE sl.id WHEN 3 THEN sl.ultVenda ELSE timestamp'01.01.1980' END) AS ultVenda_l3,
max(CASE sl.id WHEN 4 THEN sl.ultVenda ELSE timestamp'01.01.1980' END) AS ultVenda_l4,
max(CASE sl.id WHEN 5 THEN sl.ultVenda ELSE timestamp'01.01.1980' END) AS ultVenda_l5,
max(CASE sl.id WHEN 6 THEN sl.ultVenda ELSE timestamp'01.01.1980' END) AS ultVenda_l6,
max(CASE sl.id WHEN 1 THEN sl.ultCompra ELSE timestamp'01.01.1980' END) AS ultCompra_l1,
max(CASE sl.id WHEN 2 THEN sl.ultCompra ELSE timestamp'01.01.1980' END) AS ultCompra_l2,
max(CASE sl.id WHEN 3 THEN sl.ultCompra ELSE timestamp'01.01.1980' END) AS ultCompra_l3,
max(CASE sl.id WHEN 4 THEN sl.ultCompra ELSE timestamp'01.01.1980' END) AS ultCompra_l4,
max(CASE sl.id WHEN 5 THEN sl.ultCompra ELSE timestamp'01.01.1980' END) AS ultCompra_l5,
max(CASE sl.id WHEN 6 THEN sl.ultCompra ELSE timestamp'01.01.1980' END) AS ultCompra_l6,
max(CASE sl.id WHEN 1 THEN sl.ultForn ELSE '' END) AS ultForn_l1,
max(CASE sl.id WHEN 2 THEN sl.ultForn ELSE '' END) AS ultForn_l2,
max(CASE sl.id WHEN 3 THEN sl.ultForn ELSE '' END) AS ultForn_l3,
max(CASE sl.id WHEN 4 THEN sl.ultForn ELSE '' END) AS ultForn_l4,
max(CASE sl.id WHEN 5 THEN sl.ultForn ELSE '' END) AS ultForn_l5,
max(CASE sl.id WHEN 6 THEN sl.ultForn ELSE '' END) AS ultForn_l6,
max(CASE sl.id WHEN 1 THEN sl.vendas_periodo ELSE 0 END) AS vendas_periodo_l1,
max(CASE sl.id WHEN 2 THEN sl.vendas_periodo ELSE 0 END) AS vendas_periodo_l2,
max(CASE sl.id WHEN 3 THEN sl.vendas_periodo ELSE 0 END) AS vendas_periodo_l3,
max(CASE sl.id WHEN 4 THEN sl.vendas_periodo ELSE 0 END) AS vendas_periodo_l4,
max(CASE sl.id WHEN 5 THEN sl.vendas_periodo ELSE 0 END) AS vendas_periodo_l5,
max(CASE sl.id WHEN 6 THEN sl.vendas_periodo ELSE 0 END) AS vendas_periodo_l6,
max(CASE sl.id WHEN 1 THEN sl.maximo ELSE 0 END) AS maximo_l1,
max(CASE sl.id WHEN 2 THEN sl.maximo ELSE 0 END) AS maximo_l2,
max(CASE sl.id WHEN 3 THEN sl.maximo ELSE 0 END) AS maximo_l3,
max(CASE sl.id WHEN 4 THEN sl.maximo ELSE 0 END) AS maximo_l4,
max(CASE sl.id WHEN 5 THEN sl.maximo ELSE 0 END) AS maximo_l5,
max(CASE sl.id WHEN 6 THEN sl.maximo ELSE 0 END) AS maximo_l6,
max(CASE sl.id WHEN 1 THEN sl.giro ELSE 0 END) AS giro_l1,
max(CASE sl.id WHEN 2 THEN sl.giro ELSE 0 END) AS giro_l2,
max(CASE sl.id WHEN 3 THEN sl.giro ELSE 0 END) AS giro_l3,
max(CASE sl.id WHEN 4 THEN sl.giro ELSE 0 END) AS giro_l4,
max(CASE sl.id WHEN 5 THEN sl.giro ELSE 0 END) AS giro_l5,
max(CASE sl.id WHEN 6 THEN sl.giro ELSE 0 END) AS giro_l6,
max(CASE sl.id WHEN 1 THEN sl.qtde ELSE 0 END) AS qtd_l1,
max(CASE sl.id WHEN 2 THEN sl.qtde ELSE 0 END) AS qtd_l2,
max(CASE sl.id WHEN 3 THEN sl.qtde ELSE 0 END) AS qtd_l3,
max(CASE sl.id WHEN 4 THEN sl.qtde ELSE 0 END) AS qtd_l4,
max(CASE sl.id WHEN 5 THEN sl.qtde ELSE 0 END) AS qtd_l5,
max(CASE sl.id WHEN 6 THEN sl.qtde ELSE 0 END) AS qtd_l6,
max(CASE sl.id WHEN 1 THEN sl.sugestao ELSE 0 END) AS sugestao_l1,
max(CASE sl.id WHEN 2 THEN sl.sugestao ELSE 0 END) AS sugestao_l2,
max(CASE sl.id WHEN 3 THEN sl.sugestao ELSE 0 END) AS sugestao_l3,
max(CASE sl.id WHEN 4 THEN sl.sugestao ELSE 0 END) AS sugestao_l4,
max(CASE sl.id WHEN 5 THEN sl.sugestao ELSE 0 END) AS sugestao_l5,
max(CASE sl.id WHEN 6 THEN sl.sugestao ELSE 0 END) AS sugestao_l6
FROM "Grades" gr
INNER JOIN suprimento_loja sl ON sl.grade_id = gr.id
group by gr.id
order by gr.id
And the view 'suprimento_loja' is that query used before in the function.

The only thing you can do now to speed up the query - remake the function to take less time.
It PostgreSQL 9.3 you will be able to use your second query variant with LATERAL, but it wont be significantly faster.

This is only the edited body (untested, hope I didn't make any typos ;-):
WITH vendas as (
SELECT "inventario_id"
, SUM(coalesce("quantidade", 0)) as vendas_periodo
FROM "WVItens" vwi
WHERE vwi."ultimoDownload" between current_timestamp - (SELECT to_interval(vendas_dias)) AND current_timestamp
AND coalesce("status", '') = ''
GROUP BY "inventario_id"
)
SELECT into qtde1, vendasdiae1, maximoe1, ultvendae1, ultcomprae1, ultforne1, classee1, vendase1, giroe1
cast("quantidadeAtual" as integer)
, cast("vendasPorDia" as integer)
, cast("maximoEmDias" as integer)
, "dataUltimaVenda"
, "dataUltimaCompra"
, "ultimoFornecedor"
, "classe"
, cast(vendas_periodo as integer)
, coalesce("giro", 0)
FROM "Inventarios" inv
JOIN "Lojas" lo ON inv."estoque_id" = lo."estoque1_id"
JOIN vendas ve ON inv."id" = ve."inventario_id"
WHERE coalesce( inv."status", '') = ''
AND lo."id" = lojaId
AND "grade_id" = gradeId
;
WITH vendas as (
SELECT "inventario_id"
, SUM(coalesce("quantidade", 0)) as vendas_periodo
FROM "WVItens" vwi
WHERE vwi."ultimoDownload" between current_timestamp - (SELECT to_interval(vendas_dias))
AND current_timestamp
AND coalesce("status", '') = ''
GROUP BY "inventario_id"
)
SELECT into qtde2, vendasdiae2, maximoe2, ultvendae2, ultcomprae2, ultforne2, vendase2, giroe2
cast("quantidadeAtual" as integer)
, cast("vendasPorDia" as integer)
, cast("maximoEmDias" as integer)
, "dataUltimaVenda"
, "dataUltimaCompra"
, "ultimoFornecedor"
, cast(vendas_periodo as integer)
, coalesce("giro", 0)
FROM "Inventarios" inv
JOIN "Lojas" lo ON inv."estoque_id" = lo."estoque2_id"
JOIN vendas ve ON inv."id" = vendas."inventario_id"
WHERE coalesce( inv."status", '') = ''
AND lo."id" = lojaId
AND "grade_id" = gradeId
;
WITH vendas as (
SELECT "inventario_id"
, SUM(coalesce("quantidade", 0)) as vendas_periodo
FROM "WVItens" vwi
WHERE vwi."ultimoDownload" between current_timestamp - (SELECT to_interval(vendas_dias))
AND current_timestamp
AND coalesce("status", '') = ''
GROUP BY "inventario_id"
)
SELECT into qtde3, vendasdiae3, maximoe3, ultvendae3, ultcomprae3, ultforne3, vendase3, giroe3
cast("quantidadeAtual" as integer)
, cast("vendasPorDia" as integer)
, cast("maximoEmDias" as integer)
, "dataUltimaVenda"
, "dataUltimaCompra"
, "ultimoFornecedor"
, cast(vendas_periodo as integer)
, coalesce("giro", 0)
FROM "Inventarios" inv
JOIN "Lojas" lo ON inv."estoque_id" = lo."estoque2_id"
JOIN vendas ve ON inv."id" = vendas."inventario_id"
WHERE coalesce( inv."status", '') = ''
AND lo."id" = lojaId
AND "grade_id" = gradeId
;
At first glance, It appears you are doing exactly the same query three times, with different constants, which to me looks subobtimate.

Related

Tableau-Generated Query Not Hitting the Optimal Table Index

I have a tableau-generated query that looks like:
SELECT (((DATEPART(year,(CASE
WHEN 0 = ISDATE(CAST([table1].[M_Date] AS VARCHAR)) THEN NULL
ELSE DATEADD(day, DATEDIFF(day, 0, CAST(CAST([table1].[M_Date] AS VARCHAR) as datetime)), 0) END)) * 10000) + (DATEPART(month,(CASE
WHEN 0 = ISDATE(CAST([table1].[M_Date] AS VARCHAR)) THEN NULL
ELSE DATEADD(day, DATEDIFF(day, 0, CAST(CAST([table1].[M_Date] AS VARCHAR) as datetime)), 0) END)) * 100)) + DATEPART(day,(CASE
WHEN 0 = ISDATE(CAST([table1].[M_Date] AS VARCHAR)) THEN NULL
ELSE DATEADD(day, DATEDIFF(day, 0, CAST(CAST([table1].[M_Date] AS VARCHAR) as datetime)), 0) END))) AS [md:M_Date:ok]
FROM [tbl].[table] [table1]
GROUP BY (((DATEPART(year,(CASE
WHEN 0 = ISDATE(CAST([table1].[M_Date] AS VARCHAR)) THEN NULL
ELSE DATEADD(day, DATEDIFF(day, 0, CAST(CAST([table1].[M_Date] AS VARCHAR) as datetime)), 0) END)) * 10000) + (DATEPART(month,(CASE
WHEN 0 = ISDATE(CAST([table1].[M_Date] AS VARCHAR)) THEN NULL
ELSE DATEADD(day, DATEDIFF(day, 0, CAST(CAST([table1].[M_Date] AS VARCHAR) as datetime)), 0) END)) * 100)) + DATEPART(day,(CASE
WHEN 0 = ISDATE(CAST([table1].[M_Date] AS VARCHAR)) THEN NULL
ELSE DATEADD(day, DATEDIFF(day, 0, CAST(CAST([table1].[M_Date] AS VARCHAR) as datetime)), 0) END)))
table 'table' has two indexes:
A clustered index over the columns [M_Date], [Team], [Player], [Second].
A non-unique, non-clustered index over the columns [Player], [M_Date], [Team]
When I look at the Execution Plan for the query, it tells me that the second index is being used. This seems strange to me because I thought that an index could only be used if the columns involved form 'a leftmost prefix of the index' (as explained here) which this query does not. If anyone could explain what it is I am not understanding, or if this is just an odd case where the incorrect index is getting used, your help would be much appreciated!

Problems trying to return records from SELECT statement using Postgresql

I am NEW to Postgresql. I downloaded v9.5 of Postgresql a couple of days ago and finding this DB pretty challenging in just trying to get my result set back from a pretty length SELECT statement. I'm using the pgAdmin III product and hoping that I can see my result data but to no avail.
I've inherited this code and trying to make changes and trying NOT to HARD CODE the lines where the variables are being used if I can avoid it.
I've been googling about this for 2 days but again to no avail and I've tried many different variations but still not doing something right. Any help/direction would be appreciated.
Here is the error I'm getting:
********** Error **********
ERROR: query has no destination for result data
SQL state: 42601
Hint: If you want to discard the results of a SELECT, use PERFORM instead.
Context: PL/pgSQL function getrecords() line 14 at SQL statement
Here is my code (sorry for the length of the query):
CREATE OR REPLACE FUNCTION getRecords() RETURNS TABLE (
title TEXT,
Number_of_visits BIGINT,
Daily_Visit_Total_hours TEXT,
First_Aid_Visits BIGINT,
First_Aid_Total_hours TEXT,
Major_Accident_Visits BIGINT,
Major_Accident_Total_hours TEXT,
Illness_Visits BIGINT,
Illness_Total_hours TEXT,
Medication_Administration_Visits BIGINT,
Medication_Administration_Total_hours TEXT,
Specialization_Visits BIGINT,
Specialization_Total_hours TEXT,
Diabetic_Visits BIGINT,
Diabetic_Total_Hours TEXT) AS $$
#variable_conflict use_variable
DECLARE
SYEAR_DATE NUMERIC;
START_DATE DATE;
END_DATE DATE;
SCHOOL_ID NUMERIC;
BEGIN
SYEAR_DATE := 2015;
START_DATE := '2015-08-01';
END_DATE := '2015-12-31';
SCHOOL_ID := 002;
SELECT DISTINCT
'999 - DISTRICT TOTALS',
dailyVisitTotal.count as Number_of_visits,
round (dailyVisitTotal.duration_total / 60, 2) || 'hrs' as Daily_Visit_Total_hours,
firstAid.count as First_Aid_Visits,
round (firstAid.duration_total / 60, 2) || 'hrs' as First_Aid_Total_hours,
majorAcc.count as Major_Accident_Visits,
round (majorAcc.duration_total / 60, 2) || 'hrs' as Major_Accident_Total_hours,
illness.count as Illness_Visits,
round (illness.duration_total / 60, 2) || 'hrs' as Illness_Total_hours,
medicationAdminTotal.count as Medication_Administration_Visits,
round (medicationAdminTotal.duration_total / 60, 2) || 'hrs' as Medication_Administration_Total_hours,
specTotal.count as Specialization_Visits,
round (specTotal.duration_total / 60, 2) || 'hrs' as Specialization_Total_hours,
diabeticTotal.count as Diabetic_Visits,
round (diabeticTotal.duration_total / 60, 2) || 'hrs' as Diabetic_Total_Hours
FROM student_enrollment se
LEFT JOIN (
SELECT
se.syear,
count(*),
sum(coalesce(log_field20::numeric, 0)) as duration_total
FROM custom_field_log_entries sle
INNER JOIN student_enrollment se
on (sle.source_id=se.student_id
and se.custom_9 is null
and se.syear=SYEAR_DATE
--and se.syear=2015
and se.end_date is null)
WHERE
--student_field_id = 400000941
legacy_field_id = 400000941
and log_field2::date between START_DATE and END_DATE
--and log_field2::date between '2015-08-01' and '2015-12-31'
and (log_field20 ~ '^[0-9]+$' or log_field20 is null)
GROUP BY se.syear
) dailyVisitTotal
on (se.syear = dailyVisitTotal.syear)
LEFT JOIN (
SELECT
se.syear,
count(*),
sum(coalesce(log_field20::numeric, 0)) as duration_total
FROM custom_field_log_entries sle
INNER JOIN student_enrollment se
on (sle.source_id=se.student_id
and se.custom_9 is null
and se.syear=SYEAR_DATE
--and se.syear=2015
and se.end_date is null)
WHERE
--student_field_id = 400000941
legacy_field_id=400000941
and log_field2::date between START_DATE and END_DATE
--and log_field2::date between '2015-08-01' and '2015-12-31'
and (log_field20 ~ '^[0-9]+$' or log_field20 is null)
and log_field4='Y'
GROUP BY se.syear
) firstAid
on (se.syear = firstAid.syear)
LEFT JOIN (
SELECT
se.syear,
count(*),
sum(coalesce(log_field20::numeric, 0)) as duration_total
FROM custom_field_log_entries sle
INNER JOIN student_enrollment se
on (sle.source_id=se.student_id
and se.custom_9 is null
and se.syear=SYEAR_DATE
--and se.syear=2015
and se.end_date is null)
WHERE
--student_field_id = 400000941
legacy_field_id=400000941
and log_field2::date between START_DATE and END_DATE
--and log_field2::date between '2015-08-01' and '2015-12-31'
and (log_field20 ~ '^[0-9]+$' or log_field20 is null)
and log_field9='Y'
GROUP BY se.syear
) majorAcc
on (se.syear = majorAcc.syear)
LEFT JOIN (
SELECT
se.syear,
count(*),
sum(coalesce(log_field20::numeric, 0)) as duration_total
FROM custom_field_log_entries sle
INNER JOIN student_enrollment se
on (sle.source_id=se.student_id
and se.custom_9 is null
and se.syear=SYEAR_DATE
--and se.syear=2015
and se.end_date is null)
WHERE
--student_field_id = 400000941
legacy_field_id=400000941
and log_field2::date between START_DATE and END_DATE
--and log_field2::date between '2015-08-01' and '2015-12-31'
and (log_field20 ~ '^[0-9]+$' or log_field20 is null)
and log_field5='Y'
GROUP BY se.syear
) illness
on (se.syear = illness.syear)
LEFT JOIN (
SELECT
se.syear,
count(*),
sum(coalesce(log_field2::numeric, 0)) as duration_total
FROM custom_field_log_entries sle
INNER JOIN student_enrollment se
on (sle.source_id=se.student_id
and se.custom_9 is null
and se.syear=SYEAR_DATE
--and se.syear=2015
and se.end_date is null)
WHERE
--student_field_id = 400001237
legacy_field_id=400001237
and log_field5::date between START_DATE and END_DATE
--and log_field5::date between '2015-08-01' and '2015-12-31'
and (log_field2 ~ '^[0-9]+$' or log_field2 is null)
GROUP BY se.syear
) medicationAdminTotal
on (se.syear = medicationAdminTotal.syear)
LEFT JOIN (
SELECT
se.syear,
count(*),
sum(coalesce(log_field11::numeric, 0)) as duration_total
FROM custom_field_log_entries sle
INNER JOIN student_enrollment se
on (sle.source_id=se.student_id
and se.custom_9 is null
and se.syear=SYEAR_DATE
--and se.syear=2015
and se.end_date is null)
WHERE
--student_field_id = 400009202
legacy_field_id=400009202
and log_field3::date between START_DATE and END_DATE
--and log_field3::date between '2015-08-01' and '2015-12-31'
and (log_field11 ~ '^[0-9]+$' or log_field11 is null)
GROUP BY se.syear
) specTotal
on (se.syear = specTotal.syear)
LEFT JOIN (
SELECT
se.syear,
count(*),
sum(coalesce(log_field14::numeric, 0)) as duration_total
FROM custom_field_log_entries sle
INNER JOIN student_enrollment se
on (sle.source_id=se.student_id
and se.custom_9 is null
and se.syear=SYEAR_DATE
--and se.syear=2015
and se.end_date is null)
WHERE
--student_field_id = 400009003
legacy_field_id=400009003
and log_field1::date between START_DATE and END_DATE
--and log_field1::date between '2015-08-01' and '2015-12-31'
and (log_field14 ~ '^[0-9]+$' or log_field14 is null)
GROUP BY se.syear
) diabeticTotal
on (se.syear = diabeticTotal.syear)
WHERE
se.syear = SYEAR_DATE
--se.syear = 2015
and se.end_date is null
and se.custom_9 is null
and se.syear=SYEAR_DATE
--and se.syear=2015
and se.end_date is null
and (
specTotal.duration_total is not null
or dailyVisitTotal.duration_total is not null
or diabeticTotal.duration_total is not null
or medicationAdminTotal.duration_total is not null
)
ORDER BY 1;
END $$ LANGUAGE 'plpgsql';
SELECT * FROM getRecords();
Add RETURN QUERY before your query. That should tell postgres to return the records from your query.
BEGIN
SYEAR_DATE := 2015;
START_DATE := '2015-08-01';
END_DATE := '2015-12-31';
SCHOOL_ID := 002;
RETURN QUERY SELECT DISTINCT
'999 - DISTRICT TOTALS',
dailyVisitTotal.count as Number_of_visits,
round (dailyVisitTotal.duration_total / 60, 2) || 'hrs' as Daily_Visit_Total_hours,
firstAid.count as First_Aid_Visits,
...

PostgreSQL Query with dynamic columns and counts from join

I'm probably overthinking this, because I'm not really sure where to start... But here goes:
I have the following
Tables
students
assessments
students_assessments
Expected output
First query for "Attempts"
student_id | Assessment 1 | Assessment 2 | Assessment 3 | Assessment 4
1 3 1 2 0
2 1 0 0 0
3 2 1 1 0
4 5 3 3 0
5 1 5 0 0
6 2 1 2 0
Second query for "passed"
student_id | Assessment 1 | Assessment 2 | Assessment 3 | Assessment 4
1 t t f f
2 t t f f
3 t t f f
4 t t t f
5 t t f f
6 t t t f
The part that is tripping me up is not doing a join for EVERY assessment, and not even defining the columns manually but rather "generating" each column for assessments that exist.
I feel like it's simple, and I am just too overworked to figure it out right now :) thank you in advance for your help, and here's a SQL Fiddle of data as an example
Simple query for "Attempts",
select student_id,sum(case when assessment_id=1 then 1 else 0 end) as "Assessment 1",
sum(case when assessment_id=2 then 1 else 0 end) as "Assessment 2",
sum(case when assessment_id=3 then 1 else 0 end) as "Assessment 3",
sum(case when assessment_id=4 then 1 else 0 end) as "Assessment 4",
sum(case when assessment_id=5 then 1 else 0 end) as "Assessment 5",
sum(case when assessment_id=6 then 1 else 0 end) as "Assessment 6"
from assessments_students
group by student_id
order by student_id
In crosstab() function also, need to define columns name explicitly like "Assessment 1","Assessment 2" and so on.
Or write custom function for creating dynamic query, and execute using EXECUTE statement.
DROP FUNCTION get_Attempts() ;
CREATE OR REPLACE FUNCTION get_Attempts() RETURNS text AS
$BODY$
DECLARE
r1 record;
str_query text := '';
BEGIN
str_query :='select student_id,';
FOR r1 IN SELECT "_id" , "name" FROM Assessments
LOOP
str_query:= str_query ||
'sum(case when assessment_id=' || r1."_id" || ' then 1 else 0 end) as "' || r1.name ||'",' ;
END LOOP;
str_query:=trim( trailing ',' from str_query); -- remove last semicolon
str_query:= str_query || ' from assessments_students group by student_id order by student_id';
return str_query;
END
$BODY$
LANGUAGE 'plpgsql' ;
SELECT * FROM get_Attempts();
Second query for "passed"
select student_id,
max(case when assessment_id=1 and passed='t' then 't' else 'f' end) as "Assessment 1",
max(case when assessment_id=2 and passed='t' then 't' else 'f' end) as "Assessment 2",
max(case when assessment_id=3 and passed='t' then 't' else 'f' end) as "Assessment 3",
max(case when assessment_id=4 and passed='t' then 't' else 'f' end) as "Assessment 4",
max(case when assessment_id=5 and passed='t' then 't' else 'f' end) as "Assessment 5",
max(case when assessment_id=6 and passed='t' then 't' else 'f' end) as "Assessment 6"
from assessments_students
group by student_id
order by student_id
and it's function look likes,
DROP FUNCTION get_passed() ;
CREATE OR REPLACE FUNCTION get_passed() RETURNS text AS
$BODY$
DECLARE
r1 record;
str_query text := '';
BEGIN
str_query :='select student_id,';
FOR r1 IN SELECT "_id" , "name" FROM Assessments
LOOP
str_query:= str_query ||
'max(case when assessment_id=' || r1."_id" || ' and passed=''t'' then ''t'' else ''f'' end) as "' || r1.name ||'",' ;
END LOOP;
str_query:=trim( trailing ',' from str_query); -- remove last semicolon
str_query:= str_query || ' from assessments_students group by student_id order by student_id';
return str_query;
END
$BODY$
LANGUAGE 'plpgsql' ;
SELECT * FROM get_passed();
SELECT * FROM crosstab(
'Select studentid, assessmentname,count (studentassessmentid) from ....[do ur joins here] group by studentid,assessmentname order by 1,2' AS ct (studentid, assesment1, assessment2,assesent3,assessment4);
I realized it doesn't work anymore. I'm using PostgreSQL 12.
So here you cannot return non-predefined table type (I mean variable columns) either select from varying char.
An example with using anonymous code block, crosstab and temp tables.
Cursors are redundand, I was solving a task that meant of using them.
CREATE EXTENSION IF NOT EXISTS tablefunc;
DO
$$
DECLARE
movie_probe CURSOR FOR
SELECT m.name movie_name, count(c.id) cinema_count
FROM movies m
JOIN sessions s ON m.id = s.movie_id
JOIN cinema_halls ch ON s.cinema_hall_id = ch.id
JOIN cinemas c ON ch.cinema_id = c.id
GROUP BY m.name
HAVING count(c.name) > 1
ORDER BY count(c.name) DESC;
movie_rec RECORD;
movie_columns TEXT DEFAULT '';
cinemas_probe CURSOR (cond_movie_name TEXT) FOR
SELECT m.name movie_name, c.name cinema_name
FROM movies m
JOIN sessions s ON m.id = s.movie_id
JOIN cinema_halls ch ON s.cinema_hall_id = ch.id
JOIN cinemas c ON ch.cinema_id = c.id
WHERE cond_movie_name = m.name
ORDER BY c.name;
cinema_rec RECORD;
cinema_row_counter INT DEFAULT 0;
BEGIN
DROP TABLE IF EXISTS cinema_multiples_aev;
CREATE TEMP TABLE cinema_multiples_aev (
row_id INT,
movie_name TEXT,
cinema_name TEXT
);
OPEN movie_probe;
LOOP
FETCH movie_probe INTO movie_rec;
EXIT WHEN NOT FOUND;
OPEN cinemas_probe(movie_rec.movie_name);
LOOP
FETCH cinemas_probe INTO cinema_rec;
EXIT WHEN NOT FOUND;
cinema_row_counter := cinema_row_counter + 1;
INSERT INTO cinema_multiples_aev (row_id, movie_name, cinema_name)
VALUES (cinema_row_counter, cinema_rec.movie_name, cinema_rec.cinema_name);
END LOOP;
CLOSE cinemas_probe;
cinema_row_counter := 0;
movie_columns := movie_columns || ', "' || movie_rec.movie_name || '" TEXT';
END LOOP;
CLOSE movie_probe;
movie_columns := substring(movie_columns FROM 2);
DROP TABLE IF EXISTS movie_multiples;
EXECUTE format('CREATE TEMP TABLE movie_multiples(row_id INT, %s)', movie_columns);
EXECUTE format(E'
INSERT INTO movie_multiples
SELECT *
FROM crosstab(\'select row_id, movie_name, cinema_name
from cinema_multiples_aev
order by 1,2\')
AS cinema_multiples_aev(row_id INT, %s);
', movie_columns, movie_columns);
ALTER TABLE movie_multiples DROP COLUMN row_id;
END
$$ LANGUAGE plpgsql;
SELECT *
FROM movie_multiples;
DROP TABLE IF EXISTS movie_multiples;
DROP TABLE IF EXISTS cinema_multiples_aev;
If it's confusing for the lack of strusture, everything could be found here github

Working with stored procedures in Visual Studio 2012

We have a person search stored procedure in our database, which I want to map into Visual Studio 2012 in my edmx file. The stored procedure returns the rows that satisfy the search and it sets a return code. When I execute the stored procedure manually I get the 4 rows I expect and I get a return code of 0.
I am using 2012, EF 5, and Entity Framework components in the framework.
When I select the stored procedure via UpdateModelFromDatabase and add it to my project, instead of defining the usual {storedProcedureName}_Result and returning that, it is translated to return only an integer. This prevents me from using the stored procedure to actually get to the rows to display them.
Interestingly enough, we have a test PersonSearch stored procedure which happens to be broken, but it is the same stored procedure with some internal changes. It still returns the results of the search AND sets the return code. When I pull that second stored procedure in, it does as expected and creates the stored procedure as returning the {storedProcedureName}_Result and returning the rows.
Has anyone seen this issue and how do I work around this issue? I need this first stored procedure to return the rows, not the return code.
Follow Up
I came across this question and had my DBA look at it. But making similar changes to our stored procedure still has EF returning an integer instead of a complex object.
I also ran the sproc with all fields null and it returned the empty table structure in addition to the return code.
This is the stored procedure:
USE [ourdatabase]
GO
/****** Object: StoredProcedure [dbo].[usp_Person_SearchPerson] Script Date: 01/30/2013 11:46:31 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_Person_SearchPerson]
#firstName nvarchar(50), --OR
#lastName nvarchar(50), --OR
#companyName nvarchar(150), --OR
#phoneNumber1 nvarchar(50), --OR
#phoneNumber2 nvarchar(50), --OR
#email nvarchar(100), --OR
#franchiseSetId uniqueidentifier, --AND
#recordSourceId uniqueidentifier --AND
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ReturnTable TABLE
(
PersonID UNIQUEIDENTIFIER,
FirstName NVARCHAR(50),
LastName NVARCHAR(50),
CompanyName NVARCHAR(150),
EmailAddress NVARCHAR(100),
PhoneNumber1 NVARCHAR(50),
PhoneNumber2 NVARCHAR(50),
Address1 NVARCHAR(50),
City NVARCHAR(100),
State NVARCHAR(50),
PostalCode NVARCHAR(20),
Score INT
)
-- flags to be used instead of calling the function udf_Strings_IsNullOrEmpty repeatedly
Declare
#firstNamebit bit, --OR
#lastNamebit bit, --OR
#companyNamebit bit, --OR
#phoneNumber1bit bit, --OR
#phoneNumber2bit bit, --OR
#emailbit bit, --OR
#franchiseSetIdbit bit, --AND
#recordSourceIdbit bit,
#rowID int
Insert into AppToolData..SearchLog
(
firstname ,
lastname ,
companyName ,
phoneNumber1 ,
phoneNumber2 ,
email ,
franchiseSetId ,
recordSourceID ,
StartTime_UTC
)
Values
(
#firstname ,
#lastname ,
#companyName ,
#phoneNumber1 ,
#phoneNumber2 ,
#email ,
#franchiseSetId ,
#recordSourceID ,
SYSDATETIMEOFFSET()
)
Select #rowID = SCOPE_IDENTITY()
-- working set to accumulate Person records meeting search criteria
--Declare #People table
Create Table #People
(
PersonID uniqueIdentifier
)
--work set of distinct person reocrds from previous working set
Declare #DistinctPeople table
(
PersonID uniqueIdentifier not null Primary Key
)
--Set flags
Select -- 0 = False (Is Not Null) 1 = True (Is Null)
#firstNamebit = dbo.udf_Strings_IsNullOrEmpty(#firstName),
#lastNamebit = dbo.udf_Strings_IsNullOrEmpty(#lastName),
#companyNamebit = dbo.udf_Strings_IsNullOrEmpty(#companyName),
#phoneNumber1bit = dbo.udf_Strings_IsNullOrEmpty(#phoneNumber1),
#phoneNumber2bit = dbo.udf_Strings_IsNullOrEmpty(#phoneNumber2),
#emailbit = dbo.udf_Strings_IsNullOrEmpty(#email)
DECLARE #MinimumWeight INT
SET #MinimumWeight = 1
DECLARE #AvailableWeight INT
SET #AvailableWeight = 0
If #franchiseSetId is not null
Begin
Select #firstName = '%'+#firstName+'%'
Select #lastName = '%'+#lastName+'%'
End
Else
Begin
Select #firstName = #firstName+'%'
Select #lastName = #lastName+'%'
End
If #franchiseSetId is null
Begin
-- first name provided, last name not provided, phone number not provided
IF #firstNamebit = 0 and #lastNamebit = 1 and #phoneNumber1bit = 1
BEGIN
SET #AvailableWeight = #AvailableWeight + 15 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where first name is a partial string match
Insert into #People
Select PersonID from Person p
Where (PatIndex(#firstName, p.FirstName)>0)
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
-- first name not provided, last name provided, phone number not provided
Else IF #firstNamebit = 1 and #lastNamebit = 0 and #phoneNumber1bit = 1
BEGIN
SET #AvailableWeight = #AvailableWeight + 20 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where last name is a partial string match
Insert into #People
Select PersonID from Person p
Where
(PatIndex(#lastName, p.lastName)>0)
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
-- first name provided, last name provided, phone number not provided
Else IF #firstNamebit = 0 and #lastNamebit = 0 and #phoneNumber1bit = 1
BEGIN
SET #AvailableWeight = #AvailableWeight + 30 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where first & last name are a partial string match
Insert into #People
Select PersonID from Person p
Where
(
(PatIndex(#firstName, p.FirstName)>0)
and
(PatIndex(#lastName, p.lastName)>0)
)
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
-- first name provided, last name not provided, phone number provided
IF #firstNamebit = 0 and #lastNamebit = 1 and #phoneNumber1bit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 45 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where first name is a partial string match
-- and Phone Number is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where
(PatIndex(#firstName, p.FirstName)>0)
and
pn1.Number = #PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
-- first name not provided, last name provided, phone number provided
Else IF #firstNamebit = 1 and #lastNamebit = 0 and #phoneNumber1bit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 50 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where last name is a partial string match
-- and Phone Number is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where
(PatIndex(#lastName, p.LastName)>0)
and
pn1.Number = #PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
-- first name provided, last name provided, phone number provided
Else IF #firstNamebit = 0 and #lastNamebit = 0 and #phoneNumber1bit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 65 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where first & last name are a partial string match
-- and Phone Number is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where
(
(PatIndex(#firstName, p.FirstName)>0)
and
(PatIndex(#lastName, p.LastName)>0)
)
and
pn1.Number = #PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
-- first name not provided, last name not provided, phone number provided
Else IF #firstNamebit = 1 and #lastNamebit = 1 and #phoneNumber1bit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 30 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where Phone Number is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where
pn1.Number = #PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
End
Else -- Indicates WORKCENTER/Drybook search
Begin
IF #firstNamebit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 15
-- Add records where first name is a partial string match
Insert into #People
Select PersonID from Person p
Where (PatIndex(#firstName, p.FirstName)>0)
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
IF #lastNamebit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 20
-- Add records where last name is a partial string match
Insert into #People
Select PersonID from Person p
Where
(PatIndex(#lastName, p.lastName)>0)
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
IF #phoneNumber1bit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 30
-- Add records where Phone Number 1 is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where pn1.Number = #PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
End
IF #phoneNumber2bit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 30
-- Add records where Phone Number 2 is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where pn1.Number = #PhoneNumber2
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
IF #emailbit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 40
-- Add records where Email is an exact match
Insert into #People
Select
p.PersonId
from Person p
LEFT OUTER JOIN
PersonEmailAddress pea WITH (NOLOCK)
ON p.PersonId=pea.PersonId
LEFT OUTER JOIN
EmailAddress ea WITH (NOLOCK)
ON pea.EmailAddressId=ea.EmailAddressId
Where ea.[Address] = #email
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
IF #companyNamebit = 0
BEGIN
SET #AvailableWeight = #AvailableWeight + 10
-- Add records where Company Name is an exact match
Insert into #People
Select
p.PersonId
from Person p
LEFT OUTER JOIN
Company c WITH (NOLOCK)
ON p.CompanyId=c.CompanyId
Where c.Name = #companyName
AND
(
p.RecordSourceId = Coalesce(#recordSourceId, p.RecordSourceId)
--(#recordSourceId IS NULL)
--OR
--(p.RecordSourceId = #recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(#franchiseSetId, p.FranchiseSetId)
--(#franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = #franchiseSetId)
)
END
If #franchiseSetId is not null
Begin
-- WORKCENTER -- do not return results that are less than a 40% match of what was passed in
SET #MinimumWeight = #AvailableWeight * 0.4
End
Else
Begin
-- ClaimsEntry -- do not return results that are less than a 60% match of what was passed in
SET #MinimumWeight = #AvailableWeight * 0.6
End
-- get list of unique records
Insert into #DistinctPeople
Select Distinct PersonID from #People order by PersonID
INSERT INTO #ReturnTable (PersonID, FirstName, LastName, CompanyName, EmailAddress, PhoneNumber1, PhoneNumber2, Score)
(
SELECT
DistinctPeople.PersonId,
p.FirstName,
p.LastName,
c.Name,
ea.[Address],
null as PhoneNumber1,
null as PhoneNumber2,
Score =
(
--first name score
(
(CASE WHEN #firstNamebit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN PatIndex(#firstName, p.FirstName)>0 THEN 1 ELSE 0 END)
*
15
)
+
--last name score
(
(CASE WHEN #lastNamebit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN PatIndex(#lastName, p.LastName)>0 THEN 1 ELSE 0 END)
*
20
)
+
--email score
(
(CASE WHEN #emailbit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN ea.[Address] = #email THEN 1 ELSE 0 END)
*
40
)
+
--company score
(
(CASE WHEN #companyNamebit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN PatIndex(#companyName, c.Name)>0 THEN 1 ELSE 0 END)
*
10
)
)
FROM
#DistinctPeople DistinctPeople
LEFT OUTER JOIN
Person p WITH (NOLOCK)
ON DistinctPeople.PersonId=p.PersonId
LEFT OUTER JOIN
PersonEmailAddress pea WITH (NOLOCK)
ON p.PersonId=pea.PersonId
LEFT OUTER JOIN
EmailAddress ea WITH (NOLOCK)
ON pea.EmailAddressId=ea.EmailAddressId
LEFT OUTER JOIN Company c WITH (NOLOCK)
ON p.CompanyId=c.CompanyId
)
--If neither Phone number was passed as a parameter, the scores will not change
-- We can get rid of records that will not be returned
If #phoneNumber1bit = 1 and #phoneNumber2bit = 1
Begin
-- update the phone number scores, the actual phone number values
-- can be in either the first or second position
UPDATE rt
SET Score = Score +
(
(CASE WHEN #phoneNumber1bit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN rt.PhoneNumber1 = #phoneNumber1 THEN 1
WHEN rt.PhoneNumber2 = #phoneNumber1 THEN 1 ELSE 0 END)
*
30
)
+
--phone 2 score
(
(CASE WHEN #phoneNumber2bit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN rt.PhoneNumber1 = #phoneNumber2 THEN 1
WHEN rt.PhoneNumber2 = #phoneNumber2 THEN 1 ELSE 0 END)
*
30
)
FROM #ReturnTable rt
-- clear out the records we no longer care about
DELETE FROM #ReturnTable WHERE Score < #MinimumWeight
End
UPDATE rt
SET rt.PhoneNumber1 =
(
select top 1 xpn1.number
from PersonPhoneNumber xppn1 WITH (NOLOCK)
LEFT OUTER JOIN
PhoneNumber xpn1 WITH (NOLOCK)
on xppn1.PhoneNumberId =xpn1.PhoneNumberId
where xppn1.PersonId = rt.PersonID
order by (CASE
WHEN xpn1.Number = #phoneNumber1 then -999
else xppn1.SequenceNumber
end )
)
FROM #ReturnTable rt
UPDATE rt
SET rt.PhoneNumber2 =
(
select top 1 xpn1.number from PersonPhoneNumber xppn1 WITH (NOLOCK)
LEFT OUTER JOIN PhoneNumber xpn1 WITH (NOLOCK) on xppn1.PhoneNumberId =xpn1.PhoneNumberId
where xppn1.PersonId = rt.PersonID
and rt.PhoneNumber1 != xpn1.Number
order by (CASE
WHEN xpn1.Number = #phoneNumber2 then -998
else xppn1.SequenceNumber end )
)
FROM #ReturnTable rt
-- update the phone number scores, the actual phone number values can be in either the first or second position
UPDATE rt
SET Score = Score +
(
(CASE WHEN #phoneNumber1bit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN rt.PhoneNumber1 = #phoneNumber1 THEN 1
WHEN rt.PhoneNumber2 = #phoneNumber1 THEN 1 ELSE 0 END)
*
30
)
+
--phone 2 score
(
(CASE WHEN #phoneNumber2bit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN rt.PhoneNumber1 = #phoneNumber2 THEN 1
WHEN rt.PhoneNumber2 = #phoneNumber2 THEN 1 ELSE 0 END)
*
30
)
FROM #ReturnTable rt
-- clear out the records we no longer care about
DELETE FROM #ReturnTable WHERE Score < #MinimumWeight
UPDATE rt
SET Address1 = a.Address1,
City = a.City,
State = s.Abbreviation,
PostalCode = a.PostalCode
FROM #ReturnTable rt
OUTER APPLY
(
SELECT TOP 1 *
FROM PersonAddress pa WITH (NOLOCK)
WHERE pa.PersonId = rt.PersonID
ORDER BY pa.SequenceNumber
) ppa
LEFT JOIN Address a WITH (NOLOCK) on ppa.AddressId = a.AddressId
LEFT JOIN State s WITH (NOLOCK) on a.StateId = s.StateId
Update AppToolData..SearchLog
Set EndTime_UTC = SYSDATETIMEOFFSET()
Where rowid = #rowid
-- return only those that meet the minimum score/weight requirements
Delete FROM #ReturnTable WHERE Score < #MinimumWeight
SELECT * FROM #ReturnTable
--order by Score Desc
END
Based on information from cadrell0 and our own tests we found the following:
A stored procedure that is generating a table and returning rows from that table are doing this only at runtime. When called by Entity Framework with fmtonly it throws an error because the runtime object is not created.
We added FMTONLY OFF to our stored procedure which allowed Entity Framework to see the format of the table and, thus, the format for the complex object.
This allowed me to add the stored procedure, get the correct returned object, and now I'm able to use the sproc to execute our search on the database side of the fence.
This was important to us as the original code is using this and our code HAD to use it.

How to design T-SQL query to calculate sum in one pass?

I am trying to develop a T-SQL query which will do the following:
ROUND(100 * A / B, 1)
Simple in concept, but it's tricky because of possible B=0 denominator and also because of A and B variables. What I expect is a percent value like 93.2 (given in this format without %). Or even 932 would be acceptable since I could convert it later.
But instead, I'm currently getting 151, which is the number of records.
A = CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1 ELSE 0 END
B = CASE WHEN [Date_Completed] IS NOT NULL THEN 1 ELSE 0 END
My current logic only divides A/B if B is not equal to zero. Can you please help me fix this? p.s. all fields above are from the same table A.
I tried:
SELECT CASE WHEN t.VarB<>0 THEN ROUND(100 * t.VarA / t.VarB, 1)
ELSE 0 /* or whatever you'd want to return in this case */
END
FROM (SELECT CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1
ELSE 0
END AS VarA,
CASE WHEN [Date_Completed] IS NOT NULL THEN 1
ELSE 0
END AS VarB
FROM EXCEL.Batch_Records A) t
But I got 33000 rows returned instead of just one, where each row = 100 or 0.
Good idea, Conrad! I tested your solution and it works if I just want that one value. But what I didn't tell you was that there are additional values I need returned from same query. When I tried adding in the other value calculations, I got syntax errors. So here is my current query. How should htis be rewritten please?
select
SUM(CASE WHEN A.DATE_RECEIVED IS NOT NULL THEN 1 ELSE 0 END) AS NUM_RECEIVED,
SUM(CASE WHEN [Date_Completed] IS NOT NULL THEN 1 ELSE 0 END) AS NUM_COMPLETE_OF_OPENED,
SUM(CASE WHEN A.DATE_COMPLETED IS NOT NULL THEN 1 ELSE 0 END) AS NUM_COMPLETED_IN_MONTH,
SUM(CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1 ELSE 0 END) AS NUM_WITHOUT_ERROR,
round(100 * a/b , 1)
from
(select
sum(CASE
WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN
1.0
ELSE 0.0 END) A,
sum(CASE WHEN [Date_Completed] IS NOT NULL THEN
1.0 ELSE 0.0 END) B
FROM EXCEL.Batch_Records a
LEFT JOIN EXCEL.QC_CODES d ON a.Part_Number = d.CODE_ID
WHERE (a.[Group] = #GROUP or #GROUP = '' OR #GROUP IS NULL) AND A.Date_Received >= #STARTDATE AND A.Date_Received <= #ENDDATE
Conrad correctly advised me that #TEMP1 was an empty table. But now I populated it and successfully designed this query with his help:
SET #STARTDATE = '1/1/11'
SET #ENDDATE = '1/31/11'
SET #GROUP = 'INTERMEDIATES_FISH'
--SET #TABLE_TITLE = 'BATCH RECORD SUCCESS RATE'
--SET #DEPT = 'QC'
IF EXISTS(SELECT * FROM TEMPDB.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE '#TEMP1%')
DROP TABLE #TEMP1
--CREATE TABLE #TEMP1 ( MFG int , MFG2 int , QC int, QC2 INT , [Group] NVARCHAR(MAX), [Date_Completed] datetime, Date_Received datetime)
SELECT
MFG, MFG2, QC, QC2, [GROUP], [DATE_COMPLETED], [DATE_RECEIVED]
INTO #TEMP1
FROM EXCEL.Batch_Records a
WHERE (a.[Group] = #GROUP or #GROUP = '' OR #GROUP IS NULL) AND A.Date_Received >= #STARTDATE AND A.Date_Received <= #ENDDATE
------------------------------------------
;WITH CTE AS
(
SELECT
CASE
WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN
1.0
ELSE 0.0 END A,
CASE WHEN [Date_Completed] IS NOT NULL THEN 1.0 ELSE 0.0 END B,
CASE WHEN A.Date_Received IS NOT NULL THEN 1 ELSE 0 END NUM_RECEIVED,
CASE WHEN [Date_Completed] IS NOT NULL THEN 1 ELSE 0 END NUM_COMPLETE_OF_OPENED,
CASE WHEN A.DATE_COMPLETED IS NOT NULL THEN 1 ELSE 0 END NUM_COMPLETED_IN_MONTH,
CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1 ELSE 0 END AS NUM_WITHOUT_ERROR
FROM
#TEMP1 a
--WHERE (a.[Group] = #GROUP or #GROUP = '' OR #GROUP IS NULL) AND A.Date_Received >= #STARTDATE AND A.Date_Received <= #ENDDATE
)
select
round(100 * SUM(A)/SUM(b) , 1) ,
SUM(NUM_RECEIVED) NUM_RECEIVED,
SUM(NUM_COMPLETE_OF_OPENED) NUM_COMPLETE_OF_OPENED,
SUM(NUM_COMPLETED_IN_MONTH) NUM_COMPLETED_IN_MONTH,
SUM(NUM_WITHOUT_ERROR) NUM_WITHOUT_ERROR
FROM CTE
Basically you need to use SUM() to get the sum. You should also use 1.0 and 0.0 so you get decimal values.
You should also do the SUM before the Division
UPDATE
Since you're adding in a number of SUM(CASE statements its probably more readable to move the CASE statments out to a CTE.
CREATE TABLE #Batch_Records (
MFG int ,
MFG2 int ,
QC int,
QC2 INT ,
[Group] int,
[Date_Completed] datetime,
Date_Received datetime)
INSERT INTO #Batch_Records (MFG , MFG2 , QC , QC2 , [Group] , [Date_Completed] , Date_Received )
VALUES (1,null,null,null,1,'1/4/2011','2/4/2011'),
(null,null,null,null,1,'2/2/2011','3/4/2011'),
(1,null,null,null,1,'3/6/2011','4/3/2011'),
(null,null,null,null,1,NULL,'5/4/2011'),
(1,null,null,null,1,'5/4/2011','6/6/2011'),
(1,null,null,null,1,NULL,'7/4/2011')
DECLARE #GROUP int
DECLARE #STARTDATE DateTime
DECLARE #ENDDATE DateTime
SET #GROUP = 1
SET #STARTDATE = '1/1/2001'
SET #ENDDATE = '1/1/2012'
;WITH CTE AS
(
SELECT
CASE
WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN
1.0
ELSE 0.0 END A,
CASE WHEN [Date_Completed] IS NOT NULL THEN
1.0 ELSE 0.0 END B,
CASE WHEN A.Date_Received IS NOT NULL THEN 1 ELSE 0 END NUM_RECEIVED,
CASE WHEN [Date_Completed] IS NOT NULL THEN 1 ELSE 0 END NUM_COMPLETE_OF_OPENED,
CASE WHEN A.DATE_COMPLETED IS NOT NULL THEN 1 ELSE 0 END NUM_COMPLETED_IN_MONTH,
CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1 ELSE 0 END AS NUM_WITHOUT_ERROR
FROM
#Batch_Records a
WHERE
(a.[Group] = #GROUP or #GROUP = '' OR #GROUP IS NULL)
AND A.Date_Received >= #STARTDATE AND A.Date_Received <= #ENDDATE
)
select
round(100 * SUM(A)/SUM(b) , 1) ,
SUM(NUM_RECEIVED) NUM_RECEIVED,
SUM(NUM_COMPLETE_OF_OPENED) NUM_COMPLETE_OF_OPENED,
SUM(NUM_COMPLETED_IN_MONTH) NUM_COMPLETED_IN_MONTH,
SUM(NUM_WITHOUT_ERROR) NUM_WITHOUT_ERROR
FROM CTE
DROP TABLE #Batch_Records