condense results into 1 result under a certain limit - sql

So, I have a result set that has a percentage of the total in 1 column and a name in the other column.
So for example -
Name | Percentage
Jill | 12
Sam | 24
Steve| 2
Jeff | 3
Elvis | 59
I am trying to condense any result thats less than 15% into on row,
so my result would be
Name | Percentage
Everyone else| 17
Sam | 24
Elvis | 59
Thanks!

You can use APPLY :
SELECT tt.Name, SUM([Percentage]) AS [Percentage]
FROM table t CROSS APPLY
( VALUES (CASE WHEN [Percentage] < 15
THEN 'Everyone else'
ELSE Name
END)
) tt(Name)
GROUP BY tt.Name;

Use a case expression in a derived table (the sub-query) to put all less than 15% people together. GROUP BY its result:
select name, sum(Percentage)
from
(
select case when Percentage > 15 then name
else 'Everyone else'
end as name,
Percentage
from tablename
) dt
group by name

For such a simple condition, you can just use CASE expressions:
select (case when percentage < 15 then 'Everyone else'
else name
end) as name,
sum(percentage) as percentage
from t
group by (case when percentage < 15 then 'Everyone else'
else name
end)
order by sum(percentage) asc;

Related

Aggregating columns inside a CASE statement

I have a case such that
~id ~from ~to ~label ~weight
100 A B knows 2
100 A B knows 3
100 A B knows 4
But I want only the weight for maximum Date.
How can I modify the below CASE statement such that only 1 entry is there for an ID.
Query:
(
select distinct
CASE WHEN *some-condition* as "~id"
,CASE *some-condition* as "~from"
,CASE *some-condition* as "~to"
,CASE *some-condition* as "~label"
,CASE ??? as "weight"
from
(select
dense_rank() over(partition by t.job_id order by start_time desc) rnk,
t.Date,
t.job_id,
t.start_time,
t.end_time,
t.dep_id,
t.table_name
.....
t.region_id,
from Table1 t
,Tabel2 J
where t.JOB_ID=J.JOB_ID
)
where rnk=1
order by JOB_ID,table_name
)
where "~id" is NOT NULL and "~label" is NOT NULL and "~from" is NOT NULL and "~to" is NOT NULL;
;
Table t
job_id Date table_name ....... dep_id weight
100 2020-10-20 abc 1 2
100 2020-10-20 abc 2 3
100 2020-10-20 abc 3 4
100 2020-10-20 abc 4 10
100 2020-10-19 abc 3 2
Output weight in the result should be corresponding to maximum dep_id.
~id ~from ~to ~label ~weight
100 A B knows 10
It's quite hard to come up with a solution since you didn't state how ~id, ~from, ~to, ~label are calculated. You should be able to achieve your desired output with window functions, i.e. FIRST_VALUE():
...
,CASE *some-condition* as "~label"
,FIRST_VALUE(weight)OVER(ORDER BY dep_id desc) "weight"
...
You may need to add a PARTITION BY clause depending if you want to have the first value overall or depending on some other conditions as well.

Calculate product of column values on the basis of other column in SQL Server

I have a table
Tid Did value
------------------
1 123 100
1 234 200
2 123 323
2 234 233
All tids have dids as 123 and 234. So for every tid having dids 123 and 234 I want the product of corresponding values
The output table will be
Tid Product
------------------
1 20000 (product of 100 and 200)
2 75259 (product of 323 and 233)
Any help?
select tid,
min(case when did = 123 then value end)
* min(case when did = 234 then value end) product
from my_table
group by tid
To get the data for multiple rows combined (based on tid) you use GROUP BY.
Because you're grouping by tid, you have to use an aggregate function to do anything with other values from the individual rows. If implied assumptions hold (exactly 1 row matching each did for each tid) then it doesn't matter much what aggregate function you use; min is as good as anything.
Within the aggregation, you use CASE logic to select value for the required did (and NULL for all other rows in the tid group).
Then just do the math.
You can use some arithmetic to get the product per tid.
select tid,exp(sum(log(value))) as prod
from t
group by tid
To do this only for tid's having did values 123 and 234, use
select tid,exp(sum(log(value))) as prod
from t
group by tid
having count(distinct case when did in (123,234) then did end) = 2
Here's a Rexster solution, based on good work of #gbn here
SELECT
Tid,
CASE
WHEN MinVal = 0 THEN 0
WHEN Neg % 2 = 1 THEN -1 * EXP(ABSMult)
ELSE EXP(ABSMult)
END
FROM
(
SELECT
Tid,
SUM(LOG(ABS(NULLIF(value, 0)))) AS ABSMult,
SUM(SIGN(CASE WHEN value < 0 THEN 1 ELSE 0 END)) AS Neg,
MIN(ABS(value)) AS MinVal
FROM
t
GROUP BY
Tid
) t2

Teradata, subquery in case

can you help me please. I need insert in case subquery, but teradata doesn't allow me this query, how can i change it (to similar query as case, like if)?
select amount, status
case
when max(amount) then
(select sum(a1.amount)+a2.amount
from payments a1
join payments a2 on a1.payment_id=a2.payment_id
where a2.status = 't'
and a1.status not like 'w'
group by a1.amount,a2.amount)
else sum(amount)
end
from payments
Amount | Status
--------| ------
10 | t
20 | w
30 | t
40 | w
50 | t
60 | t
70 | k
expected results: if amount is max then calculate amount to new column like sum(a1.amount)+a2.amount, where status for table a1 is 't' and status for a2 is not 'w'. If amount is not max, then just calculate all amounts from table payments.
results:
--for amount = 70 insert into new column (for example result) sum(all amount where status is not 'w') + sum(all amount where status is 't').
--For other amount < 70 insert into new column result sum(all amount).
Thank you for your help.
This will help I guess
select amt,status,(case when amt=max_amt then w_sum else total_sum end)results
from (
select amt,
status,
sum(amt) over(partition by (case when status='w' and status<>'t' then 1 else 0 end ))w_sum,
sum(amt) over(partition by 1) total_sum,
max(amt) over(partition by 1) max_amt
from t st)x
Let me know if it works for you.

SQL find total count of each type in a column

I'm learning SQL and am stumped on what should be a simple query. I have a table with the following pattern:
Id | Type
------------
1 | Red
2 | Blue
3 | Blue
4 | Red
..
I would like to write a query to return a table that counts the total number of instances of each type and returns a table with the following pattern, for example, if 'Blue' occurs in 12 rows, and 'Red' occurs in 16 rows in the table above, the result would be:
Blue | Red
-----------
12 | 16
You could do it this way:
SELECT Type, COUNT(*) FROM TABLE GROUP BY Type
If you'd like to see the Types in separate columns, you could do this:
SELECT SUM(CASE WHEN Type = 'Blue' THEN 1 ELSE 0 END) AS Blue, SUM(CASE WHEN Type = 'Red' THEN 1 ELSE 0 END) AS Red FROM TABLE
I suggest using count over partition by. Here's a code I wrote to help my company check for duplicate Technician EmployeeID's and Pincodes, including count and YES/NO columns to allow filtering in excel so they can see what corrections need to be made:
select
t.TechnicianId, t.TechnicianName, t.Pincode, t.EmployeeID
, [Pincode Count] = count(t.Pincode) over (partition by t.Pincode)
, [Duplicate Pincode?] = case count(t.Pincode) over (partition by t.Pincode) when 1 then 'NO' else 'YES' end
, [EmployeeID Count] = count(t.EmployeeID) over (partition by t.EmployeeID)
, [Duplicate EmployeeID?] = case count(t.EmployeeID) over (partition by t.EmployeeID) when 1 then 'NO' else 'YES' end
from Technicians t
group by t.TechnicianId, t.TechnicianName, t.Pincode, t.EmployeeID
order by 4

SQL: Compare rows in a same table

I'm trying to compare rows in a single table
and figure out if "addr" and "zip" under the same id are same or different.
id | addr | zip
------+----------+----------
1 | 123 | 0000
1 | 123 | 0000
1 | 123 | 0001
2 | 222 | 1000
2 | 221 | 1000
So the result should say id 1 has valid addr and invalid zip
id 2 has invalid addr and valid zip.
Any hint will be appreciated! Thank you!!
The query...
SELECT id, COUNT(DISTINCT addr), COUNT(DISTINCT zip)
FROM YOUR_TABLE
GROUP BY id
...should give the following result on your example data...
1, 1, 2
2, 2, 1
The numbers in bold greater than 1 indicate "invalid" items.
If you want to actually filter on this, you can use HAVING clause, for example:
SELECT id, COUNT(DISTINCT addr) ADDR_COUNT, COUNT(DISTINCT zip) ZIP_COUNT
FROM YOUR_TABLE
GROUP BY id
HAVING ADDR_COUNT > 1 OR ZIP_COUNT > 1
May I suggest that if you don't actually want this kind of "mismatched" data in your database, redesign your data model so duplicates cannot happen in the first place. No duplicates, no mismatches!
Group by id. Select id, COUNT(DISTINCT addr) and COUNT(DISTINCT zip) columns.
Filter the rows where the number of distinct address or zips > 1.
This will give you the ids with inconsistent duplicate data.
Example:
SELECT id, COUNT(DISTINCT addr) nAddr, COUNT(DISTINCT zip) nZip
FROM [mytable]
GROUP BY id
HAVING nAddr > 1 OR nZip > 1
Cheers,
SELECT id
, CASE s.addrcount
WHEN 1 THEN 'valid'
ELSE 'invalid' END as addrok
, CASE s.zipcount
WHEN 1 THEN 'valid'
ELSE 'invalid' END as zipok
FROM
(
SELECT id
, count(distinct addr) as addrcount
, count(distinct zip) as zipcount
FROM table1
GROUP BY id
) as s