optimising aggregates with and without a condition in ms sql - sql

I would like to get a sum from a column, with and without a condition. The code I have now is
SELECT regular.id, regular.sum as regularsum, special.sum as specialsum FROM
(SELECT Sum(stuff) as sum, id FROM table
WHERE commonCondition = true
GROUP BY id) as regular
INNER JOIN
(SELECT Sum(stuff) as sum, id FROM table
Where commonCondition = true AND specialCondition = true
GROUP BY id) as special
ON regular.id = special.id
Which works, but seems very inefficient, not to mention ugly. the table is fairly large, so some optimisation would be welcome.
How can I write this in a better, more efficent way?

I think you could do something like this:
SELECT
Sum(stuff) as regularsum,
sum(case when specialcondition=true then stuff else 0 end) as specialsum,
id FROM table
WHERE commonCondition = true
GROUP BY id
However, you'd want to test to see if it was any faster.

Related

Access query doesn't return correct values

I have a long query in Access. But it doesn't return correct values.
Because access has problem with null values. This is my query:
SELECT courses.coursename as coursename
,scores.coursecode as coursecode
,val(scores.score) as score
FROM courses,scores
where scores.timeyear='96'
and scores.dore='1'
and scores.stdcode in
(
Select stdcode
from classbandi
where classid='12'
)
and scores.coursecode=courses.coursecode
and scores.score is null
and scores.coursecode <> '7991'
order by scores.coursecode
When I run this query, this part (scores.score = '') likes not in query.
What is problem and what I must to do to solve this problem?
this query must return all null values in db that stored in scores.score table.
but it can't return any value.
access database download link
nobody can't solve this problem?!?!
You are using an MS Access database (presumably). If so, I would expect the query to look like this:
select c.coursename as coursename,
s.coursecode as coursecode,
val(s.score) as score
from courses as c inner join
scores as s
on s.coursecode = c.coursecode
where s.timeyear = "96" and
s.dore = "1" and
s.stdcode in (select cb.stdcode from classbandi as cb where cb.classid = "12") and
(s.score is null or s.score = "") and -- or whatever logic you want here
s.coursecode <> "7991"
order by s.coursecode;
I'm not sure if this actually addresses your problem. Without sample data and desired results in the question it is hard to figure out what the problem really is.
Handle isnull condition for all predicated in where clause

How to use SUM in this situation?

I have the following tables below and their schema:
INV
id, product code, name, ucost, tcost, desc, type, qoh
1,123,CPASS 700,1.00,5.00,CPASS 700 Lorem, COM,5
2,456,Shelf 5,2.00,6.00,Shelf 5 KJ, BR,3
GRP
id,type,desc
1,COM,COMPASS
2,BR,SHELF
Currently I have a query like this:
SELECT INV.*,GRP.DESCR AS CATEGORY
FROM INV LEFT JOIN GRP ON INV.TYPE = GRP.TYPE
WHERE INV.QOH = 0
There is no problems with that query.
Right now,I want to know the SUM of the TCOST of every INV record where their QOH is 0.
In this situation, does that I mean all I have to do is to write a separate query like the one below:
SELECT SUM(TCOST)
FROM INV
WHERE QOH = 0
Does it make any sense for me to try and combine those two queries as one ?
First understand that SUM is the aggregate function hence either you can run the Query like
(SELECT SUM(TCOST) FROM INV WHERE QOH=0) as total
This will return Sum of TCOST in INV Table for mentioned condition.
Another approach is finding the Sum based on the some column (e.g. Type)
you could write query like
SELECT Type , SUM(TCOST) FROM INV WHERE QOH=0 GROUP BY type ;
Its not clear on what criteria you want to sum . But I think above two approaches would provide you fare idea .
Mmm, you could maybe use a correlated query, though i'm not sure it's the best approach since I'm not sure I understand what your attempting to do:
SELECT INV.*,
GRP.DESCR AS CATEGORY ,
(SELECT SUM(TCOST) FROM INV WHERE QOH=0) as your_sum
FROM INV LEFT JOIN GRP ON INV.TYPE = GRP.TYPE
WHERE INV.QOH = 0
If you want only one value for the sum(), then your query is fine. If you want a new column with the sum, then use window functions:
SELECT INV.*, GRP.DESCR AS CATEGORY,
SUM(INV.TCOST) OVER () as sum_at_zero
FROM INV LEFT JOIN
GRP
ON INV.TYPE = GRP.TYPE
WHERE INV.QOH = 0;
It does not make sense to combine the queries by adding a row to the first one, because the columns are very different. A SQL result set requires that all rows have the same columns.

SQL GROUP BY function returning incorrect SUM amount

I've been working on this problem, researching what I could be doing wrong but I can't seem to find an answer or fault in the code that I've written. I'm currently extracting data from a MS SQL Server database, with a WHERE clause successfully filtering the results to what I want. I get roughly 4 rows per employee, and want to add together a value column. The moment I add the GROUP BY clause against the employee ID, and put a SUM against the value, I'm getting a number that is completely wrong. I suspect the SQL code is ignoring my WHERE clause.
Below is a small selection of data:
hr_empl_code hr_doll_paid
1 20.5
1 51.25
1 102.49
1 560
I expect that a GROUP BY and SUM clause would give me the value of 734.24. The value I'm given is 211461.12. Through troubleshooting, I added a COUNT(*) column to my query to work out how many lines it's running against, and it's giving a result of 1152, furthering reinforces my belief that it's ignoring my WHERE clause.
My SQL code is as below. Most of it has been generated by the front-end application that I'm running it from, so there is some additional code in there that I believe does assist the query.
SELECT DISTINCT
T000.hr_empl_code,
SUM(T175.hr_doll_paid)
FROM
hrtempnm T000,
qmvempms T001,
hrtmspay T166,
hrtpaytp T175,
hrtptype T177
WHERE 1 = 1
AND T000.hr_empl_code = T001.hr_empl_code
AND T001.hr_empl_code = T166.hr_empl_code
AND T001.hr_empl_code = T175.hr_empl_code
AND T001.hr_ploy_ment = T166.hr_ploy_ment
AND T001.hr_ploy_ment = T175.hr_ploy_ment
AND T175.hr_paym_code = T177.hr_paym_code
AND T166.hr_pyrl_code = 'f' AND T166.hr_paid_dati = 20180404
AND (T175.hr_paym_type = 'd' OR T175.hr_paym_type = 't')
GROUP BY T000.hr_empl_code
ORDER BY hr_empl_code
I'm really lost where it could be going wrong. I have stripped out the additional WHERE AND and brought it down to just T166.hr_empl_code = T175.hr_empl_code, but it doesn't make a different.
By no means am I any expert in SQL Server and queries, but I have decent grasp on the technology. Any help would be very appreciated!
Group by is not wrong, how you are using it is wrong.
SELECT
T000.hr_empl_code,
T.totpaid
FROM
hrtempnm T000
inner join (SELECT
hr_empl_code,
SUM(hr_doll_paid) as totPaid
FROM
hrtpaytp T175
where hr_paym_type = 'd' OR hr_paym_type = 't'
GROUP BY hr_empl_code
) T on t.hr_empl_code = T000.hr_empl_code
where exists
(select * from qmvempms T001,
hrtmspay T166,
hrtpaytp T175,
hrtptype T177
WHERE T000.hr_empl_code = T001.hr_empl_code
AND T001.hr_empl_code = T166.hr_empl_code
AND T001.hr_empl_code = T175.hr_empl_code
AND T001.hr_ploy_ment = T166.hr_ploy_ment
AND T001.hr_ploy_ment = T175.hr_ploy_ment
AND T175.hr_paym_code = T177.hr_paym_code
AND T166.hr_pyrl_code = 'f' AND T166.hr_paid_dati = 20180404
)
ORDER BY hr_empl_code
Note: It would be more clear if you have used joins instead of old style joining with where.

Postgres SQL - performance issue with boolean field

In my table plin_korisnik, I have field active which is defined as boolean type.
I'm trying to execute this query to fetch data from that table and two other tables:
SELECT
pk.omm AS omm,
pk.br_plin AS br_plin,
pk.naziv AS naziv,
pk.ulica||' '||pk.kbr AS adresa,
pk.pu||' - '||pk.naziv_pu AS mjesto,
po.datum AS datum,
CASE WHEN po.stanje >= 999999 THEN NULL ELSE po.stanje END AS stanje,
po.napomena AS napomena,
po.plin_postar AS laus,
pp.ime||' '||pp.prezime AS postar
FROM plin_korisnik pk
INNER JOIN
plin_ocitanje po ON pk.omm = po.omm
INNER JOIN plin_postar pp ON pp.laus = po.plin_postar
WHERE po.datum>='2017-01-26'
AND po.datum<='2017-01-26'
AND pk.tip='p'
AND pk.active = TRUE
ORDER BY po.datum, pk.naziv
but query takes to much time (like forever; I interrupted it after half an hour), but when I remove pk.active = TRUE test from WHERE clause, then query executes with expected speed. I had try to cast boolean type to integer, but problem remains.
I'd appreciate it if someone could explain how to use a boolean field in this and similar queries. active field is not indexed, maybe it should be, please help.
EDIT:
After few hours of thinking I came out with this solution which use WITH clause:
WITH pk AS (
SELECT * FROM plin_korisnik WHERE active AND tip='p'
)
SELECT
pk.omm AS omm,
pk.br_plin AS br_plin,
pk.naziv AS naziv,
pk.ulica||' '||pk.kbr AS adresa,
pk.pu||' - '||pk.naziv_pu AS mjesto,
po.datum AS datum,
CASE WHEN po.stanje >= 999999 THEN NULL ELSE po.stanje END AS stanje,
po.napomena AS napomena,
po.plin_postar AS laus,
pp.ime||' '||pp.prezime AS postar
FROM pk
INNER JOIN
plin_ocitanje po ON pk.omm = po.omm
INNER JOIN plin_postar pp ON pp.laus = po.plin_postar
WHERE po.datum>='2017-01-26'
AND po.datum<='2017-01-26'
ORDER BY po.datum, pk.naziv;
I think you may make it faster if you change the order in the where clause, start with the initial table.
An index on pk.active and on po.datum will absolutely help.
You may want to consider putting the po.datum in the inner join, instead of the where.
po.datum>='2017-01-26'
AND po.datum<='2017-01-26'
AND pk.tip='p'
AND pk.active = TRUE
Will be:
pk.active = TRUE
AND pk.tip='p'
AND po.datum>='2017-01-26'
AND po.datum<='2017-01-26'

Case Statement as vals Outer Apply

I am trying to add a computed column to a table. Currently I have the following CASE statement building a calculated column in a SELECT statement,
--but I want to use this column to determine subsequent columns (sooo.. adding a computed column is somewhat a workaround to avoid complex CTE that i'm not sure i can figure out - let me know if CTE or functions is a better way to go)
--- I want the CASE statement to be a computed column in the table itself
SELECT top 1000
L.[MsgDate]
,C.[AlarmType]
,L.[Type]
,L.[UsrStr1]
,L.[UsrStr4]
,L.[UsrStr5]
,L.[UsrStr12]
,L.[UsrStr15]
,CASE
WHEN EXISTS
(
SELECT *
FROM Breinigsville.dbo.SCADA_SR S
WHERE S.SCADA_SR_TAG = L.UsrStr15 and
((L.[UsrStr4]='analog' and C.[AlarmType] like '%HH%') or (L.[UsrStr4]='status'))
)
THEN 1
ELSE 0
END AS [Safety]
FROM [Breinigsville].[dbo].[LMFW] L
full outer join [Breinigsville].[dbo].[_AcknowledgedAlarms] C
on
L.SeqNo=C.SeqNo2
WHERE (
L.[Type]='Ack' AND
L.UsrStr12 LIKE '%CCXOS%' AND
L.UsrStr12 NOT LIKE '%CCXOS5' AND
L.UsrStr12 NOT LIKE '%CCXOS6' AND
L.UsrStr12 NOT LIKE '%CCXOS9' AND
L.UsrStr12 NOT LIKE '%CCXOS12' AND
L.MsgDate>getdate()-1
)
order by L.SeqNo desc
Use outer apply:
FROM [Breinigsville].[dbo].[LMFW] L full outer join
[Breinigsville].[dbo].[_AcknowledgedAlarms] C
on L.SeqNo = C.SeqNo2 OUTER APPLY
(SELECT (CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END) as Safety
FROM Breinigsville.dbo.SCADA_SR S
WHERE S.SCADA_SR_TAG = L.UsrStr15 and
((L.[UsrStr4] = 'analog' and C.[AlarmType] like '%HH%') or
(L.[UsrStr4] = 'status')
)
) vals
Then you can use vals.Safety anywhere in the query.
Note: this version uses count(*). If performance is at all a concern, then you can get what you want using an additional subquery. I answered this way, because the structure of the query seems easier to follow.
Incidentally, you cannot easily put a subquery in as a computed column. You can do it, but it requires creating a user-defined function, and using that for the computed column. OUTER APPLY is definitely simpler, and you can even put this logic into a table-valued function or view.