How to sum multiple rows based on the id filter criteria? - sum

I have table with record_id and record_value. Query should return all id's and values but at the same time I need to return sum for specific group of id's. Here is example of my data:
record_id record_value
54 3
56 0
78 11
98 7
103 1
78 0
44 0
67 1
68 3
69 1
Query that I have returns rows with id's and values. I would like to get some of these columns as well in query result. Here is what I tried:
SELECT
record_id,
record_value
CASE
WHEN record_id IN ('54','56','67','68','69') THEN SUM(record_value)
ELSE ''
END AS RowSum
FROM Records
RowSum should return 19 but instead I'm getting an error:
SQL Error [257] [37000]: Implicit conversion from datatype 'VARCHAR' to 'NUMERIC' is not allowed. Use the CONVERT function to run this query.
I use Sybase database with DBeaver.

You can't use multiple results in one query. You can try with an UNION ALL
If you use CASE then both WHERE clauses should have the same type. You have used a NUMERIC (for SUM) an VARCHAR (for empty string ''). You need to unify them.
The code you might use is:
SELECT
record_id,
record_value,
FROM Records
union all
select null,
CASE
WHEN record_id IN ('54','56','67','68','69') THEN convert(varchar, SUM(record_value))
ELSE ''
END AS RowSum

Related

Two different condition for two different colums using case statement in SQL

Given a table of random numbers as follows:
** Person table schema **
Name
Marks1
Marks2
I want to return a table with similar structure and headings, where if the sum of a column is odd, the column shows the maximum value for that column, and when the sum is even, it shows the minimum value by using a case statement.
** output table schema **
Marks1
Marks2
I've tried the following code.
select Marks1,Marks2 ,
(case
when mod(sum(Marks1),2)=0 then
min(Marks1)
else max(Marks1)
end) as Marks1 ,
(case
when mod(sum(Marks2),2)=0 then
min(Marks2)
else max(Marks2)
end) as Marks2
from numbers
group by Marks1;
Sample output -
TABLE
Ash 56 45
David 45 35
Output -
56 35
As 56+45 = 101 odd number so output 56(max number). Whereas in marks2 column, 45+35 =80, even number so output 35(min number).
Can anyone tell me what's wrong with it? Thanks in advance.
Use a CTE to get your min(), max(), and sum() values. Then use case to determine what values to display.
Since your problem statement and sample results do not match, I followed your sample results to return max() on an odd sum(). You can switch this by changing the two case statements from 1 to 0.
Working fiddle
with totals as (
select sum(marks1) as marks1sum,
min(marks1) as marks1min,
max(marks1) as marks1max,
sum(marks2) as marks2sum,
min(marks2) as marks2min,
max(marks2) as marks2max
from numbers
)
select case mod(marks1sum, 2)
when 1 then marks1max
else marks1min
end as marks1,
case mod(marks2sum, 2)
when 1 then marks2max
else marks2min
end as marks2
from totals;
You are reusing marks1 and marks2 when aliasing your third and fourth column which is colliding. Try using different name.

Sql: have a column return 1 or 0 denoting if an id exists in a table for a predetermined groupID

I wrote the following SQL to create a column that I can use to populate check boxes in a Grid to manage user permissions.
SELECT access_b2b.access_id,
access_b2b.description,
'active'= CASE
WHEN access_group.group_id IS NOT NULL THEN 1
ELSE 0
END
FROM access_b2b
LEFT JOIN access_group
ON access_group.access_id = access_b2b.access_id
WHERE ( access_group.group_id = 10
OR access_group.group_id IS NULL )
However, it does not select all of the entries from access_b2b. The issues is with the last line:
where (access_group.group_id=10 or access_group.group_id is null)
Without it, i get duplicate entries returned with different active values. Also, I realized that this is not the proper condition, because an entry in access_group might exist for a different access_group.group_id, meaning that not all the remaining entries will be pulled in with the access_group.group_id is null.
I am trying to write my condition so that if does something along the lines of:
This is the format I was trying to follow:
Where For Each unique access_id in access_group
select the one where group_id=10
if no group_id=10
select any other one
end
end
Ultimately, the goal is to have a column returned with 1 or 0 denoting if the access_id exists for a predetermined group id.
Please note that throughout this explanation I used group_id=10 for simplification, it will be later replaced with a SqlParameter.
Any help is appreciated, thank you so much!
SAMPLE DATA (only useful columns shown to simplify data)
access_group
access_id group_id
27 1
27 11
28 1
28 11
33 1
33 3
33 11
43 11
44 1
44 10
44 11
...
access_b2b
access_id description
1 Add
2 Edit
3 Delete
4 List
5 Payments
6 Open Files
7 Order
8 Mod
...
Change the query to and it should work:
SELECT access_b2b.access_id,
access_b2b.description,
'active'= CASE
WHEN access_group.group_id IS NOT NULL THEN 1
ELSE 0
END
FROM access_b2b
LEFT JOIN access_group
ON access_group.access_id = access_b2b.access_id
AND ( access_group.group_id = 10
OR access_group.group_id IS NULL )
If you don't want the records to be filtered by the WHERE clause, move the condition in the JOIN.
The JOIN will keep the lines and populate them with NULL if the condition is not met, while the WHERE clause will filter the result set.

Can a SQL query be run several times on different subsets of data?

I have a table that is just random values.
I have a query that looks something like this:
SELECT COUNT(DISTINCT(Value))
FROM RandomValueTable
WHERE
Value > #lowerRange
AND
Value < #upperRange
There will be a series of ranges I need to run this for (0-20, 21-45, 46-100 etc). Before running this query, I'll know what the ranges are. Do I need to run this query several times just filling in the range variables, or is there some way I can specify all the different ranges in one query?
You can specify them in one query using group by:
select (case when value between 0 and 20 then '0-20'
when value between 21 and 45 then '21-45'
when value between 46 and 100 then '46-100'
else 'other'
end) as range,
count(*)
from RandomValueTable
group by (case when value between 0 and 20 then '0-20'
when value between 21 and 45 then '21-45'
when value between 46 and 100 then '46-100'
else 'other'
end);

Is there anything like an Excel IF Statement in SQL

Just wanted to see if there is a way to output a result that is not stored based on the addition of up to 4 fields?
Have a table that holds the count of passengers on a service for different categories, Adult, Child Infant and staff, and I want to try and out put a number based on the result of these fields that is not stored.
For example if the result of the add is >15 then output 45, if > 9 output 35. the output is the size of the coach that is required.
I know I can do it in Excel after the data is extracted but was wondering if it can be done before and included with the data?
Any suggestions and help appreciated.
Depending on what SQL program you're using, most offer the CASE WHEN statement (see this SQL Fiddle example)
CREATE TABLE CaseValues(
Value INT
)
INSERT INTO CaseValues
VALUES (1)
, (16)
, (9)
SELECT CASE WHEN Value > 15 THEN 45
WHEN Value BETWEEN 6 AND 14 THEN 35
ELSE 25 END AS Result
FROM CaseValues
You can also use CASE WHEN on multiple columns, see this example.
The Standard SQL CASE expression is the closest equivalent to the Excel IF(..) function:
SELECT
CASE WHEN Col1=Col2 THEN 'Foo'
WHEN Col1>Col2 THEN 'Bar'
WHEN Col3 Is NULL THEN Col4
ELSE 'unknown'
END As [CaseColumn]
FROM YourTable
You can do this with a query on the data:
select t.*,
(case when Adult + Child + Infant + staff > 15 then 45
when Adult + Child + Infant + staff > 9 then 35
end) as CoachSize
from t;
You can also do this using a view so it is available as if it were a table:
create view vw_t as
select t.*,
(case when Adult + Child + Infant + staff > 15 then 45
when Adult + Child + Infant + staff > 9 then 35
end) as CoachSize
from t;
And, in some databases, you can add a computed column directly into the table definition.
You can use a CASE statement. Here is the syntax.
SELECT
CASE WHEN DayOfBirth > 15
THEN 45
WHEN DayOfBirth > 9
THEN 35
ELSE
0
END
FROM BirthDaysTable

Counting non-zero values in sql

I am trying to count total number of times that each individual column is greater than zero, grouped by the driver name. Right now I have;
SELECT drivername
, COUNT(over_rpm) AS RPMViolations
, COUNT(over_spd) AS SpdViolations
, COUNT(brake_events) AS BrakeEvents
FROM performxbydriverdata
WHERE over_rpm > 0
OR over_spd > 0
OR brake_events > 0
GROUP BY drivername
This gives me all of the non-zero values but I get a display as:
Bob Smith 62 62 62
Nathan Jones 65 65 65
etc.
I'm trying to get a count of non-zeros in each individual values.. each violation should be grouped separately.
Use NULLIF to change zero to NULL, count ignores NULL
SELECT drivername,
COUNT(NULLIF(over_rpm,0)) AS RPMViolations,
COUNT(NULLIF(over_spd,0)) AS SpdViolations,
COUNT(NULLIF(brake_events,0)) AS BrakeEvents
FROM performxbydriverdata
GROUP BY drivername;
You can probably remove the WHERE clause too with this group to improve performance
OR conditions often run badly because of matching a good index
Using HAVING (as per other answers) will remove any rows where all 3 aggregates are zero which may or may not be useful for you. You can add this if you want. Saying that, the WHERE implies that at least one row has non-zero values so you don't need both WHERE and HAVING clauses
Putting filter predicate[s] inside of a Sum() function with a case statement is a useful trick anytime you need to count items based on some predicate condition.
Select DriverName,
Sum(case When over_rpm > 0 Then 1 Else 0 End) OverRpm,
Sum(case When over_spd > 0 Then 1 Else 0 End) OverSpeed,
Sum(case When brake_events > 0 Then 1 Else 0 End) BrakeEvents,
etc.
FROM performxbydriverdata
Group By DriverName