SQL: Group by Case Statement to sum Row Values - sql

I have a table that looks like below. I am trying to group by subject using a case statement for every "subject" that starts with "cf" like something like the following:
SELECT CASE WHEN subject LIKE '%cf' THEN sum(Count)
FROM table
The goal is to just drop all the extra characters following "cf" and then sum the total count and create a new row as 'Cf' with the sum of count value as shown in the desired output.
subject. count
status 2461193
priority 1042073
ta. 126295
dueDate 62560
assignee 34142
cf2122 1
cf2123. 1
cf4312. 1
cf3234. 1
cf5464. 1
desired output:
subject. count
status 2461193
priority 1042073
ta. 126295
dueDate 62560
assignee 34142
cf. 1221

You want a GROUP BY based on an expression. You also need to put the wildcard for the LIKE condition after the prefix you want, 'cf%'
SELECT CASE
WHEN subject LIKE 'cf%' THEN 'cf'
else subject
end as normalized_subject,
sum("count")
FROM the_table
group by normalized_subject
order by sum("count") desc
Using a column alias in the GROUP BY is a Postgres extension to the SQL language. In other DBMS products you would need to repeat the CASE expression in the GROUP BY (which is only more to type, but won't change performance)
Online example

Related

Count unique values between 2 dates

I created a simple database that contains dates and name values.I would like to seek some idea how to vba code to count specific value between two days.
The case is like this:
Column A: list of date
Column B:list of Name
For example:
(Col A , Col B) :row1(10/01/19 , Arctic),row2(10/02/19 , Polar),r3(10/02/19 , Polar),r4(10/02/19 , Arctic),r5(10/02/19 , Arctic),r6(10/03/19, Arctic)
Please note that the result I wish to get is:
Counr of Arctic=3
Count of Polar =1
Please note that "Polar" appears twice on 10/02/19, however, I want to count it as 1 only within the range of 10/01/19 to 10/03/19 since these two occurence of "Polar" happen in the same date. Same will be applied to "Arctic" and more names if theres any.
Please see attached image for a clearer data sample.
Thank u in advance.
SELECT T.name, COUNT(*) AS count FROM table T
WHERE T.date > date1 AND T.date < date2
GROUP BY T.name

SQL Query - how do I order part of my data in alphabetical order, and part by id

I have a small piece of data (15 records) where part of it I want ordered in alphabetical order, and part of it ordered by ID
Image 1 shows my data in the original order
After doing the query SELECT * FROM tableName ORDER BY code;
Image 2 shows my data now in alphabetical order, which is great however I would like the top 2 records to be ordered by id
Image 3 shows how I would like my data to look
Could someone help with my query please?
i assumed id is an integer. You can use conditional CASE in the ORDER BY clause.
Note for the first expression case when code in ('LUX-INT', 'LUX-CONT') then -id end desc, it will return id or NULL. As NULL will comes first in ORDER BY, I use DESC and negate the id value so that id is in ascending order
order by case when code in ('LUX-INT', 'LUX-CONT') then -id end desc, code
use case when
SELECT * FROM tableName ORDER BY case when code in ('LUX INT','LUX-CONT') then id else code end
I would write this as:
order by (case when code in ('LUX-INT', 'LUX-CONT') then 1 else 2 end), -- put the special codes first
(case when code in ('LUX-INT', 'LUX-CONT') then code end), -- order them alphabetically
id -- order the rest by id
This works regardless of the types and collations of the underlying columns.

Changing position of a row in sql

In the above t-sql table I would like very much for the Total row to appear at the bottom. I have been wracking my head against this and in all of my other Queries simply using ORDER BY Status works as Total is alphabetically much farther down the list than most of our row values.
This is not the case here and I just can't figure out how to change it
I'm pretty new to sql and I'be been having a lot of difficulty even determining how to phrase a google search. So far I've just gotten results pertaining to Order By
The results of a select query, unless an order is explicitly specified via an 'order by' clause, can be returned in any order. Moreover, the order in which they are returned is not even deterministic. Running the exact same query 3 times in succession might return the exact same result set in 3 different orderings.
So if you want a particular order to your table, you need to order it. An order by clause like
select *
from myTable t
where ...
order by case Status when 'Total' then 1 else 0 end ,
Status
would do you. The 'Total' row will float to the bottom, the other rows will be ordered in collating sequence. You can also order things arbitrarily with this technique:
select *
from myTable t
where ...
order by case Status
when 'Deceased' then 1
when 'Total' then 2
when 'Active' then 3
when 'Withdrawn' then 4
else 5
end
will list the row(s) with a status of 'Deceased' first, followed by the row(s) with a status of 'Total', then 'Active' and 'Withdrawn', and finally anything that didn't match up to an item in the list.
ORDER BY CASE WHEN STATUS = 'Total' THEN 'zzz' ELSE STATUS END
In SQL Server (and most other databases), you can use case to sort certain statūs above others:
order by
case Status
when 'Total' then 2
else 1
end
, Status
In MS Access, you can use iif:
order by
iif(Status = 'Total', 2, 1)
, Status
You can use conditional expressions in order by:
order by (case when status = 'Total' then 1 else 0 end),
status

Selected non-aggregate values must be part of the associated group

I have two tables in Teradata: Table_A and Table_B. Between them is LEFT JOIN. Afterwards I am making SELECT statement which contains attributes from both tables:
SELECT
attribute_1
attribute_2
...
attribute_N
Afterwords, I am using SUM functions to do certain calculations. These functions look something like this:
SUM (
CASE WHEN Attribute_1 > 2 THEN attribute_2*1.2
ELSE 0
End
(in this example attributes in the select part are used).
But I also use in CASE part attributes which are not in the select statement - something liek this:
SUM (
CASE WHEN Attribute_X > 2 THEN attribute_Y*1.2
ELSE 0
End
Of course at the end I am doing GROUP BY 1,2,...,N
The error I am getting is "Selected non-aggregate values must be part of the associated group."
Furtheremore, I have checked billion times the number of the selected attributes in the SELECT part, and it is N.
The question is - why am I getting this error? Is it because I am using in the SUM part i.e. CASE part attributes (attribute_X and attribute_Y) which are not included in the SELECT part?
Blueprint of the end-statement looks sthg. like this:
INSERT INTO table_new
SELECT
attribute_1,
attribute_2,
...
attribute_N,
SUM (
CASE WHEN Attribute_1 > 2 THEN attribute_2*1.2
ELSE 0
End
) as sum_a,
SUM (
CASE WHEN Attribute_X > 2 THEN attribute_Y*1.2
ELSE 0
End
) as sum_X
FROM table_a LEFT JOIN table_B
ON ...
GROUP BY 1,2,...,N
The error message suggests that you have not included all the non-aggregate columns listed in your SELECT statement in your GROUP BY expression. I'm guessing that you have more columns listed than you have "place holders".
The best way to avoid this is to explicitly name all the columns and not use the "relative positioning" syntax. In other words, rather than using GROUP BY 1,2,...N use:
GROUP BY
attribute_1,
attribute_2,
...
attribute_N
If that does not fix your problem, modify your question and show a complete query that is not working.
I have found the error - the SUM part was composed of more sub-parts. For example "amount - SUM(...) + SUM(...)". I had ti include the attributes in the "amount" part.

How to do this query in T-SQL

I have table with 3 columns A B C.
I want to select * from this table, but ordered by a specific ordering of column A.
In other words, lets' say column A contains "stack", "over", "flow".
I want to select * from this table, and order by column A in this specific ordering: "stack", "flow", "over" - which is neither ascending nor descending.
Is it possible?
You can use a CASE statement in the ORDER BY clause. For example ...
SELECT *
FROM Table
ORDER BY
CASE A
WHEN 'stack' THEN 1
WHEN 'over' THEN 2
WHEN 'flow' THEN 3
ELSE NULL
END
Check out Defining a Custom Sort Order for more details.
A couple of solutions:
Create another table with your sort order, join on Column A to the new table (which would be something like TERM as STRING, SORTORDER as INT). Because things always change, this avoids hard coding anything and is the solution I would recommend for real world use.
If you don't want the flexibility of adding new terms and orders, just use a CASE statement to transform each term into an number:
CASE A WHEN 'stack' THEN 1 WHEN 'over' THEN 2 WHEN 'flow' THEN 3 END
and use it in your ORDER BY.
If you have alot of elements with custom ordering, you could add those elements to a table and give them a value. Join with the table and each column can have a custom order value.
select
main.a,
main.b,
main.c
from dbo.tblMain main
left join tblOrder rank on rank.a = main.a
order by rank.OrderValue
If you have only 3 elements as suggested in your question, you could use a case in the order by...
select
*
from dbo.tblMain
order by case
when a='stack' then 1
when a='flow' then 2
when a='over' then 3
else 4
end