SQL Sum and Group by changing value of group - sql

How do I group values ​​and change one of them when there is more than one
Table
ID | VALUE | NAME
1 | 2 | John
1 | 5 | Carl
2 | 4 | Elis
2 | 1 | Ted
3 | 2 | James
RESULT
ID | VALUE | NAME
1 | 7 | *
2 | 5 | *
3 | 2 | James

Here is one way that should work in any database:
select id, sum(value) as value,
(case when min(name) = max(name) then min(name) else '*' end) as name
from t
group by id;

This is the others query you must try
Select ID, sum(Value) Value, NAME = ( Select b.Name + ' ' AS [text()]
From dbo.test b
Where a.ID = b.ID
ORDER BY a.ID
For XML PATH (''))
from test a
group by ID
order by ID

Related

I want row data of same id in one single row

The Table Format is like
ID | MID | PID | Quantity
1 | 1 | 2 | 3
2 | 1 | 3 | 10
3 | 2 | 2 | 11
4 | 2 | 1 | 5
I want to result as following
ID | MID | Final
1 | 1 | 2(3),3(10)
2 | 2 | 2(11),1(5)
first concate two columns and then do string_agg. Here is the demo.
with cte as
(
select
mid,
concat(pid, '(', quantity, ')') as concat_col
from table1
)
select
row_number() over (order by mid) as id,
mid,
string_agg(concat_col, ', ') as final
from cte
group by
mid
output:
| id | mid | final |
| --- | --- | ----------- |
| 1 | 1 | 2(3), 3(10) |
| 2 | 2 | 2(11), 1(5) |
If you are using older version of SQL Server then try the following
with cte as
(
select
mid,
concat(pid, '(', quantity, ')') as concat_col
from table1
)
select
row_number() over (order by mid) as id,
mid,
stuff((
select ',' + concat_col
from cte c1
where c.mid = c1.mid
for XML PATH('')
), 1, 1, '') as final
from cte c
group by
mid
select MID, string_agg(concat(PID, '(', Quantity,')'), ', ')
from dbo.Sample
group by MID
Result :
MID FINAL
1 2(3), 3(10)
2 2(11), 1(5)

how to select rows with same column_a but different column_b?

I want to select rows in sql server, there's my questions below:
Table1
--------------------------
| Name | Type |
--------------------------
| A | 1 |
| A | 2 |
| B | 1 |
| B | 3 |
| A | 3 |
| C | 1 |
| C | 3 |
| D | 1 |
| D | 2 |
| D | 3 |
| . | . |
| . | . |
Select rows like below:
Table2
--------------------------
| Name | Type |
--------------------------
| A | 1 |
| A | 2 |
| A | 3 |
| D | 1 |
| D | 2 |
| D | 3 |
| . | . |
| . | . |
The select rules is...
Show Name and Type which Type must have 1,2 and 3.
Example: A had 1,2,3 types,so i would select it.
Example: B only has 1,2 types,so i wouldn't select it.
You can use window functions for this:
select name, type
from (
select
t.*,
sum(case when type in (1, 2, 3) then 1 else 0 end)
over(partition by name) cnt
from mytable t
) t
where cnt = 3
This assumes that each (name, type) tuple occurs only once in the original table, which is consistant with your sample data.
Demo on DB Fiddle:
name | type
:--- | ---:
A | 1
A | 2
A | 3
D | 1
D | 2
D | 3
You could use INNER JOINs on the three Type columns to achieve this:
SELECT Table1.[Name],
Table1.[Type]
FROM Table1
INNER JOIN (
SELECT [Name]
FROM Table1
WHERE ([Type] = 1)
) A ON A.[Name] = Table1.[Name]
INNER JOIN (
SELECT [Name]
FROM Table1
WHERE ([Type] = 2)
) B ON B.[Name] = A.[Name]
INNER JOIN (
SELECT [Name]
FROM Table1
WHERE ([Type] = 3)
) C ON C.[Name] = A.[Name]
This outputs:
Name Type
A 1
A 2
A 3
D 1
D 2
D 3
The matching sqlfiddle.
This works by returning rows that contain [Type] = 1, and then ONLY matching rows where [Type] = 2 and [Type] = 3. Then this is joined back to your main table and the results are returned.
Get the names with group by name and set the condition in the having clause:
select * from Table1
where name in (
select name
from Table1
group by name
having count(distinct type) = 3
)
If there are for the column Type other values than 1, 2, 3 then:
select * from Table1
where type in (1, 2, 3) and name in (
select name
from Table1
where type in (1, 2, 3)
group by name
having count(distinct type) = 3
)
See the demo.
Results:
> Name | Type
> :--- | ---:
> A | 1
> A | 2
> A | 3
> D | 1
> D | 2
> D | 3
you can use string_agg if it is sql server 2017 and above or Azure SQL as below:
Select * from #yourTable yt join (
select [name], string_agg([Type], ',') as st_types
from #YourTable
group by [name] ) a
on yt.name = a.[name] and a.st_types like '%1,2,3%'
I give you this, this will work if you have:
A 1
A 2
A 3
A 2
It will then only give you B.
SELECT *
FROM Table1
WHERE Name in (
SELECT Name from
(
SELECT Name, Type, count(Name) c from Table1 where Type = 1
GROUP BY Name, Type
HAVING count(Name) = 1
UNION
SELECT Name, Type, count(Name) c from Table1 where Type = 2
GROUP by Name, Type
HAVING count(Name) = 1
UNION
SELECT Name, Type, count(Name) c from Table1 where Type = 3
GROUP by Name, Type
HAVING count(Name) = 1) t
GROUP by name
HAVING count(c) = 3)
Here is the DEMO

SQL select distinct when one column in and another column greater than

Consider the following dataset:
+---------------------+
| ID | NAME | VALUE |
+---------------------+
| 1 | a | 0.2 |
| 1 | b | 8 |
| 1 | c | 3.5 |
| 1 | d | 2.2 |
| 2 | b | 4 |
| 2 | c | 0.5 |
| 2 | d | 6 |
| 3 | a | 2 |
| 3 | b | 4 |
| 3 | c | 3.6 |
| 3 | d | 0.2 |
+---------------------+
I'm tying to develop a sql select statement that returns the top or distinct ID where NAME 'a' and 'b' both exist and both of the corresponding VALUE's are >= '1'. Thus, the desired output would be:
+---------------------+
| ID | NAME | VALUE |
+---------------------+
| 3 | a | 2 |
+----+-------+--------+
Appreciate any assistance anyone can provide.
You can try to use MIN window function and some condition to make it.
SELECT * FROM (
SELECT *,
MIN(CASE WHEN NAME = 'a' THEN [value] end) OVER(PARTITION BY ID) aVal,
MIN(CASE WHEN NAME = 'b' THEN [value] end) OVER(PARTITION BY ID) bVal
FROM T
) t1
WHERE aVal >1 and bVal >1 and aVal = [Value]
sqlfiddle
This seems like a group by and having query:
select id
from t
where name in ('a', 'b')
having count(*) = 2 and
min(value) >= 1;
No subqueries or joins are necessary.
The where clause filters the data to only look at the "a" and "b" records. The count(*) = 2 checks that both exist. If you can have duplicates, then use count(distinct name) = 2.
Then, you want the minimum value to be 1, so that is the final condition.
I am not sure why your desired results have the "a" row, but if you really want it, you can change the select to:
select id, 'a' as name,
max(case when name = 'a' then value end) as value
you can use in and sub-query
select top 1 * from t
where t.id in
(
select id from t
where name in ('a','b')
group by id
having sum(case when value>1 then 1 else 0)>=2
)
order by id

Select unique results and null

I need get all lines from table, that have unique value in certain fields and all lines, than have null in this fields. Example:
id | name | group
-----------------
1 | One | 1
2 | Two | null
3 | Three| 3
4 | Four | 2
5 | Five | 1
6 | Six | 2
7 | Seven| null
Result:
id | name | group
-----------------
1 | One | 1
2 | Two | null
3 | Three| 3
4 | Four | 2
7 | Seven| null
How to make it in one request?
select t.id, t.name, t.`group`
from tablename t
join (select `group`, min(id) as mid
from tablename
where `group` is not null
group by `group`) x on x.mid = t.id and x.`group` = t.`group`
union all
select id, name, `group`
from tablename
where `group` is null

2 listagg in one SQL Select in Oracle

I have a table in the form of :
| ID | COURSE | PASS |
---------------------------
| 1 | 1 | 1 |
| 1 | 2 | 1 |
| 1 | 3 | 1 |
| 1 | 4 | 0 |
| 1 | 5 | 0 |
and I want row in the form:
| ID | FAILED | PASSED |
---------------------------
| 1 | 4,5 | 1,2,3 |
the only i figured is something like this:
select NVL(passed.id, failed.id), passed.test, failed.test from
(select id, listagg(course, ',') within group (order by course) test from table1 where pass = 1 group by id ) passed
full outer join
(select id, listagg(course, ',') within group (order by course) test from table1 where pass = 0 group by id ) failed
on passed.id = failed.id
is there a way to do it in a single query ?
Try
select id,
listagg(case when pass = 1 then course end, ',') within group (order by course) passed,
listagg(case when pass = 0 then course end, ',') within group (order by course) failed
from table1
group by id
Here is a sqlfiddle demo