Applying Logic to Grouped SQL Results - sql

Looking for some Oracle SQL theoretical help on the best way to handle a grouped result set. I understand why it groups the way it does, but I'm trying to figure out if there's a way to
I have a table that lists the activity of some cost centers. It looks like this:
Company Object Sub July August
A 1 20 50
A 1 10 0
A 1 10 0 20
B 1 0 0
I then need to flag whether or not there was activity in August. So I'm writing a CASE statement where if August = 0 THEN 'FALSE' ELSE 'TRUE'. Then I need to group all records by Company, Object, and Sub. The Cumulative column is a SUM of both July and August. However, my output looks like this:
Company Object Sub SUM ActivityFlag
A 1 70 TRUE
A 1 10 FALSE
A 1 10 20 TRUE
B 1 0 FALSE
What I need is this:
Company Object Sub August ActivityFlag
A 1 80 TRUE
A 1 10 20 TRUE
B 1 0 FALSE
Obviously, this is a simplified example of a much larger issue, but I'm trying to think through this problem theoretically so I can apply similar logic to my actual issue.
Is there a good SQL method for adding the August amount for rows 1 and 2, and then selecting TRUE so that this appears on a single row? I hope this makes sense.

use aggregation
select company,object,sub,sum(july+august),
max(case when august>0 then 'True' else 'false' end)
from table_name group by company,object,sub

If you are flagging your detail with the case statement you can either put the case in a sum similar to:
MAX(CASE WHEN August = 0 THEN 1 ELSE 0 END)
Another way if to aggregate the flag upward in an inner query:
SELECT IsAugust = MAX(IsAugust) FROM
(
...
IsAugust = CASE WHEN August=0 THEN 1 ELSE 0 END
...
)AS X
GROUP BY...

Related

SQL SUM counting every instance and not if data is present

I have a piece of a SQL statement below:
SELECT WOCUSTFIELD.WORKORDERID, WORKORDER.ACTUALFINISHDATE,
CASE WHEN wocustfield.custfieldname LIKE '%bags%'
THEN (REPLACE( wocustfield.custfieldname, 'bags:', ''))
ELSE REPLACE( wocustfield.custfieldname, 'boxes:', '')
END AS Facility,
For each of the custfieldname that has a number > than 0 put in for Bags or Boxes I would like to count it as a Facility (visit to teh site).
Currently, it is counting every custfieldname regardless if it has a number ( 0 or >) in the field as a visit and is totaling all custfieldnames for each day.
for example, if the data look like the following for Jan 1st 2023:
Bags Boxes
Dogstation 1 3 4
Dogstation 2 0 0
Dogstation 3 5 1
Dogstation 4 2 0
Dogstation 5 0 0
I would like to have 3 Facility (visits) stations and not 5. I hope this makes sense. thanks for any help given
The COUNT aggregation counts 1 for every non-null. Zero (0) is not null, so it will count as 1. You want to do something like this:
SUM(CASE WHEN bags >0 then 1 else 0 end) as stores_with_bags
Just add in a WHERE clause. I'm not exactly sure how your table is formatted, but ex:
WHERE Bags>0 OR Boxes>0

SQL SSMS 2017 Detailed result

I´m a bit newbie to SQL, so I want to ask for possible solution how to create a query which will show the desired results.
There´s a table where are the data coming continuously from one main PLC so everything is gathered in 1 table. There are a bunch of data per 1 shift (about half million). In column "Op" are the machines represented by their IDs (Op = ID of machine). Machines are about from 1 to 218. Every machine has it´s their cycle times divided into starting process (T1), duration (T2), end process(T3) and Result. The "Result" can be interpreted as 0 - as OK, 1 - not OK, 2 - empty pallet, 3 - free flow of pallet. Those are the Results of what the PLCs are reporting directly into database´s table.
I have tried the basic statements to count these results for exact record states (0,1,2,3) and for exact machine. That´s OK but not the desired goal.
SELECT Count(*) as Result0
FROM PalletOperations
where Op = 1 and Result = 0
The expected result is to show a full list of every machines from 1 to 218 how many results were counted as 0, 1, 2 and 3. The other columns are not relevant for this time. The main goal is to show a result as every machine has its own row with the expected data of counted states result. If theres 218 machines, than I need to generate results of 218 machines separately from 1 to 218 in rows. Each row should contain the Op(name 1,2,3,4....218) with the columns of counted result for states 0,1,2,3 as mentioned above.
Any advice is welcome
I think you want conditional aggregation:
SELECT op,
SUM(CASE WHEN Result = 0 THEN 1 ELSE 0 END) as result_0,
SUM(CASE WHEN Result = 1 THEN 1 ELSE 0 END) as result_1,
SUM(CASE WHEN Result = 2 THEN 1 ELSE 0 END) as result_2,
SUM(CASE WHEN Result = 3 THEN 1 ELSE 0 END) as result_3
FROM PalletOperations
GROUP BY op;
you can use the below sql statement to get count of results per machine per result
SELECT op,Result, count(*)
FROM PalletOperations
GROUP BY op,Result;

SQL Select on condition and calculation

I've really hit a brick wall here and I'm hoping someone can point me in the right direction. I have an SQL database that looks like this:
Course Extension Max Extension 1 Extension 1 Used Extension 2 Extension 2 Used
Excel Introduction 24 12 TRUE 12 FALSE
Word Introduction 24 12 TRUE 12 TRUE
So with the above data, what I want to calculate is the Remaining Extension days, so for the first row the remaining days would be 12, as we've one block of 12 days and another 12 day block remains.
The second column would show a remaining day of zero/0 as both 12 day blocks have been used.
If both values are FALSE, then it should just display the Extension Max in days in a column as the extension hasn't been used yet.
How can I create a new column or just a variable to calculate and display the remaining days?
Any help would be appreciated, as always, thank you.
You would seem to want something like this:
select t.*,
((case when Extension1Used = 'false' then Extension1 else 0 end) +
(case when Extension2Used = 'false' then Extension2 else 0 end)
) as remaining_extension_days
from t;
Or, you could phrase this as:
select t.*,
(case when Extension1Used = 'false' and Extension2Used = 'false'
then ExtensionMax
when Extension1Used = 'false'
then Extension1
when Extension2Used = 'false'
then Extension2
else 0
end) as remaining_extension_days
from t;
The first form is simpler, and should work if the maximum extension is the sum of the individual extensions.

Converting Column Headers to Row elements

I have 2 tables I am combining and that works but I think I designed the second table wrong as I have a column for each item of what really is a multiple choice question. The query is this:
select Count(n.ID) as MemCount, u.Pay1Click, u.PayMailCC, u.PayMailCheck, u.PayPhoneACH, u.PayPhoneCC, u.PayWuFoo
from name as n inner join
UD_Demo_ORG as u on n.ID = u.ID
where n.MEMBER_TYPE like 'ORG_%' and n.CATEGORY not like '%_2' and
(u.Pay1Click = '1' or u.PayMailCC = '1' or u.PayMailCheck = '1' or u.PayPhoneACH = '1' or u.PayPhoneCC = '1' or u.PayWuFoo = '1')
group by u.Pay1Click, u.PayMailCC, u.PayMailCheck, u.PayPhoneACH, u.PayPhoneCC, u.PayWuFoo
The results come up like this:
Count Pay1Click PayMailCC PayMailCheck PayPhoneACH PayPhoneCC PayWuFoo
8 0 0 0 0 0 1
25 0 0 0 0 1 0
8 0 0 0 1 0 0
99 0 0 1 0 0 0
11 0 1 0 0 0 0
So the question is, how can I get this to 2 columns, Count and then the headers of the next 6 headers so the results look like this:
Count PaymentType
8 PayWuFoo
25 PayPhoneCC
8 PayPhoneACH
99 PayMailCheck
11 PayMailCC
Thanks.
Try this one
Select Count,
CASE WHEN Pay1Click=1 THEN 'Pay1Click'
PayMailCC=1 THEN ' PayMailCC'
PayMailCheck=1 THEN 'PayMailCheck'
PayPhoneACH=1 THEN 'PayPhoneACH'
PayPhoneCC=1 THEN 'PayPhoneCC'
PayWuFoo=1 THEN 'PayWuFoo'
END as PaymentType
FROM ......
I think indeed you made a mistake in the structure of the second table. Instead of creating a row for each multiple choice question, i would suggest transforming all those columns to a 'answer' column, so you would have the actual name of the alternative as the record in that column.
But for this, you have to change the structure of your tables, and change the way the table is populated. you should get the name of the alternative checked and put it into your table.
More on this, you could care for repetitive data in your table, so writing over and over again the same string could make your table grow larger.
if there are other things implied to the answer, other informations in the UD_Demo_ORG table, then you can normalize the table, creating a payment_dimension table or something like this, give your alternatives an ID such as
ID PaymentType OtherInfo(description, etc)...
1 PayWuFoo ...
2 PayPhoneCC ...
3 PayPhoneACH ...
4 PayMailCheck ...
5 PayMailCC ...
This is called a dimension table, and then in your records, you would have the ID of the payment type, and not the information you don't need.
So instead of a big result set, maybe you could simplify by much your query and have just
Count PaymentId
8 1
25 2
8 3
99 4
11 5
as a result set. it would make the query faster too, and if you need other information, you can then join the table and get it.
BUT if the only field you would have is the name, perhaps you could use the paymentType as the "id" in this case... just consider it. It is scalable if you separate to a dimension table.
Some references for further reading:
http://beginnersbook.com/2015/05/normalization-in-dbms/ "Normalization in DBMS"
http://searchdatamanagement.techtarget.com/answer/What-are-the-differences-between-fact-tables-and-dimension-tables-in-star-schemas "Differences between fact tables and dimensions tables"

T-SQL SUM All with a Conditional COUNT

I have a query that produces the following:
Team | Member | Cancelled | Rate
-----------------------------------
1 John FALSE 150
1 Bill TRUE 10
2 Sarah FALSE 145
2 James FALSE 110
2 Ashley TRUE 0
What I need is to select the count of members for a team where cancelled is false and the sum of the rate regardless of cancelled status...something like this:
SELECT
Team,
COUNT(Member), --WHERE Cancelled = FALSE
SUM(Rate) --All Rows
FROM
[QUERY]
GROUP BY
Team
So the result would look like this:
Team | CountOfMember | SumOfRate
----------------------------------
1 1 160
2 2 255
This is just an example. The real query has multiple complex joins. I know I could do one query for the sum of the rate and then another for the count and then join the results of those two together, but is there a simpler way that would be less taxing and not cause me to copy and paste an already complex query?
You want a conditional sum, something like this:
sum(case when cancelled = 'false' then 1 else 0 end)
The reason for using sum(). The sum() is processing the records and adding a value, either 0 or 1 for every record. The value depends on the valued of cancelled. When it is false, then the sum() increments by 1 -- counting the number of such values.
You can do something similar with count(), like this:
count(case when cancelled = 'false' then cancelled end)
The trick here is that count() counts the number of non-NULL values. The then clause can be anything that is not NULL -- cancelled, the constant 1, or some other field. Without an else, any other value is turned into NULL and not counted.
I have always preferred the sum() version over the count() version, because I think it is more explicit. In other dialects of SQL, you can sometimes shorten it to:
sum(cancelled = 'false')
which, once you get used to it, makes a lot of sense.