Update column with average values in same table using JOIN - SQL Server - sql

I have following table
[Table_01]
ID | Name | Profit | AvgProfit
------------------------------------------
1 | Donald | 1001 |
2 | Hillary | 101 |
3 | Barack | 11 |
4 | Bernie | 1 |
1 | Donald | 1002 |
2 | Hillary | 102 |
3 | Barack | 12 |
4 | Bernie | 2 |
1 | Donald | 1003 |
2 | Hillary | 103 |
3 | Barack | 13 |
4 | Bernie | 3 |
I need to add average Profit value for each person.
Result after UPDATE should be:
[Table_01]
ID | Name | Profit | AvgProfit
------------------------------------------
1 | Donald | 1001 | 1002
2 | Hillary | 101 | 102
3 | Barack | 11 | 12
4 | Bernie | 1 | 1
1 | Donald | 1002 | 1002
2 | Hillary | 102 | 102
3 | Barack | 12 | 12
4 | Bernie | 2 | 1
1 | Donald | 1003 | 1002
2 | Hillary | 103 | 102
3 | Barack | 13 | 12
4 | Bernie | 3 | 1
I do get average values using:
SELECT z1.*, AVG(Profit) OVER(PARTITION BY Name) AVERAGE
FROM Table_01 z1
order by Name
For update I've tried multiple JOIN clauses with no success.
I get various errors: using AGGREGATE in JOIN and invalid object names.
This one works in Oracle, i suppose.
UPDATE Table_01 z1
SET z1.AvgSecs = (SELECT AVG(Profit)
FROM Table_01
WHERE Name = z1.Name)
What is the syntax used in Microsoft SQL Server 2014?
QUESTION 2
I have another table which i need to update
[Table_02]
Name | AvgProfit Name | AvgProfit
--------------------- UPDATE --> ---------------------
Donald | Donald | 1002
Hillary | Hillary | 102
Barack | Barack | 12
Bernie | Bernie | 1
I wonder if this works:
UPDATE t2
SET t2.AvgProfit = t1.AvgProfit
FROM Table_02 t2
join Table_01 t1
ON t1.Name = t2.Name
"Name" is a Unique value
Great thanks for all.

You can use a CTE for the first update:
;WITH CTE AS
(
SELECT Id, AVG(Profit) OVER (PARTITION BY Name) As AvgProfit
FROM Table_01
)
UPDATE T1
SET AvgProfit = CTE.AvgProfit
FROM Table_01 T1
INNER JOIN CTE ON(T1.Id = CTE.Id)
As for your second question - The answer is yes.

Question 1 :
UPDATE Table_01 SET AvgProfit = _AvgProfit FROM
(SELECT ID , AVG(Profit) _AvgProfit FROM Table_01 GROUP BY ID )
A WHERE A.ID = Table_01.ID
Question 2 :
UPDATE Table_02 SET Table_02.AvgProfit = t1.AvgProfit
FROM Table_01 t1 WHERE t1.Name = Table_02.Name

Related

How do I join an ARRAY to a COLUMN?

I have two large tables - Table_A and Table_B - that I want to join on the ID field. "ID" in Table_A is a column and "IDs" in Table_B is an array
Table_A:
ID | City |
----+------------+
101 | London |
102 | Paris |
103 | Rome |
104 | Copenhagen |
105 | Amsterdam |
106 | Berlin |
107 | Cardiff |
108 | Lisbon |
Table_B:
Date | Sessions | IDs
------+----------+--------------
06-02 | 1 | [107,102]
06-03 | 1 | [103]
11-12 | 1 | [105,107,103]
27-06 | 1 | [104,108]
31-01 | 1 | [105]
22-04 | 1 | [106,102]
08-07 | 1 | [101,105,108]
02-10 | 1 | [105]
Desirable Output:
Date | Sessions | ID | City
------+----------+-------------+-------------
06-02 | 1 | 107 | Cardiff
| | 102 | Paris
06-03 | 1 | 103 | Rome
11-12 | 1 | 105 | Amsterdam
| | 107 | Cardiff
| | 103 | Rome
27-06 | 1 | 104 | Copenhagen
| | 108 | Lisbon
...
I have tried using inner joins with unnest and union all but nothing is working. Any help would be appreciated.
Something along those lines should yield the result you are looking for
select
date,
sessions,
array_agg(id_un) as id,
array_agg(city) as city
from table_b b, unnest (id) as id_un
left join table_a a on id_un = a.id
group by 1, 2
Consider also below approach
select date, sessions, ids as id,
array(
select city
from b.ids id
left join Table_A
using(id)
) city
from Table_B b
if applied to sample data in your question - output is

Is it possible to merge the rows of a child table and display them in a query of the primary key table

I'm working with three tables. I can easily get the first output from the query below, but I'm looking to merge the authors into one field using COALESCE if its possible (see desired result).
tblPapers:
| PaperID | Title | PublishDate | Cost |
|---------|-------|-------------|-------|
| 1 | T1 | 1/1/21 | $1.00 |
| 2 | T2 | 2/1/21 | $2.00 |
| 3 | T3 | 3/1/21 | $3.00 |
| 4 | T4 | 4/1/21 | $4.00 |
| 5 | T6 | 5/1/21 | $5.00 |
tblPaperAuthors:
| PaperAuthorsID | PaperID | AuthorID |
|----------------|---------|----------|
| 1 | 1 | 1 |
| 2 | 1 | 3 |
| 3 | 1 | 4 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
tblAuthors
| AuthorID | Author |
|----------|------------|
| 1 | John Smith |
| 2 | Tom Book |
| 3 | Jim Coast |
| 4 | John Hanes |
| 5 | Dave Wait |
1st attempt-> "SELECT tblPapers.PaperID, tblPapers.Title, tblPapers.PublishDate, tblPapers.Cost, tblAuthors.Name FROM tblAuthors INNER JOIN tblPaperAuthors ON tblAuthors.AuthorID = tblPaperAuthors.AuthorID RIGHT OUTER JOIN tblPapers ON tblPaperAuthors.PaperID = tblPapers.PaperID WHERE (tblPapers.PaperID=1)"
Results ->
PaperID Title PublishDate Cost Author(s)
1 T1 1/1/21 $1.00 John Smith
1 T1 1/1/21 $1.00 Jim Coast
1 T1 1/1/21 $1.00 John Hanes
Desired result->
PaperID Title PublishDate Cost Author(s)
1 T1 1/1/21 $1.00 John Smith, Jim Coast, John Hanes
"DECLARE #Names VARCHAR(MAX)
SELECT #Names = COALESCE(#Names + ', ', '') + [Author]
FROM tblAuthors
SELECT #Names AS [List of All Names]"

SQL select records based on not existing record

I have a table with records like this:
ID | NAME | PHASE_ID | OPERATION_ID | EXT_ID |
---+------+----------+--------------+--------+
1 | john | 5 | 5019 | aa-aaa |
2 | ann | 1 | 5048 | aa-aaa |
3 | mary | 1 | 5048 | bb-bbb |
4 | zack | 5 | 5019 | cc-ccc |
5 | paul | 1 | 5048 | cc-ccc |
6 | zoe | 2 | 5555 | aa-aaa |
7 | luke | 3 | 6666 | bb-bbb |
and I want to select all names from records having PHASE_ID=1 and OPERATION_ID=5048 for which there is no record with the same EXT_ID that have PHASE_ID=5 and OPERATION_ID=5019. In this table there is many combinations of PHASE_ID and OPERATION_ID for the same EXT_ID.
In this table name that fulfill this select would be only mary.
Any help composing that select would be appreciated.
Sounds like not exists:
select distinct name
from t
where phase_id = 1 and operation_id = 5048 and
not exists (select 1
from t t2
where t2.ext_id = t.ext_id and
t2.phase_id = 5 and t2.operation_id = 5019
);

How to remove duplicate values from oracle join?

I want to create a view that present only the results and not present the duplicates, I have 3 tables in oracle database:
The first table contain general information about a person
+-----------+-------+-------------+
| ID | Name | Birtday_date|
+-----------+-------+-------------+
| 1 | Byron | 12/10/1998 |
| 2 | Peter | 01/11/1973 |
| 4 | Jose | 05/02/2008 |
+-----------+-------+-------------+
The second table contain information about a telephone of the people in the first table.
+-------+----------+----------+----------+
| ID |ID_Person |CELL_TYPE | NUMBER |
+-------+- --------+----------+----------+
| 1221 | 1 | 3 | 099141021|
| 2221 | 1 | 2 | 099091925|
| 3222 | 1 | 1 | 098041013|
| 4321 | 2 | 1 | 088043153|
| 4561 | 2 | 2 | 090044313|
| 5678 | 4 | 1 | 092049013|
| 8990 | 4 | 2 | 098090233|
+----- -+----------+----------+----------+
The Third table contain information about a email of the people in the first table.
+------+----------+----------+---------------+
| ID |ID_Person |MAIL_TYPE | Email |
+------+- --------+----------+---------------+
| 221 | 1 | 1 |jdoe#aol.com |
| 222 | 1 | 2 |jdoe1#aol.com |
| 421 | 2 | 1 |xx12#yahoo.com |
| 451 | 2 | 2 |dsdsa#gmail.com|
| 578 | 4 | 1 |sasaw1#sdas.com|
| 899 | 4 | 2 |cvcvsd#wew.es |
+------+----------+----------+---------------+
if i do a inner join with this tables the result will do something like that
+-----+-------+-------------+----------+----------+----------+----------------+
| ID | Name | Birtday_date| CELL_TYPE| NUMBER |MAIL_TYPE|Email |
+-----+-------+-------------+----------+----------+----------+----------------+
| 1 | Byron | 12/10/1998 | 3 | 099141021|1 |jdoe#aol.com |
| 1 | Byron | 12/10/1998 | 3 | 099141021|2 |jdoe1#aol.com |
| 1 | Byron | 12/10/1998 | 2 | 099091925|1 |jdoe#aol.com |
| 1 | Byron | 12/10/1998 | 2 | 099091925|2 |jdoe1#aol.com |
| 1 | Byron | 12/10/1998 | 1 | 098041013|1 |jdoe#aol.com |
| 1 | Byron | 12/10/1998 | 1 | 098041013|2 |jdoe1#aol.com |
| 2 | Peter | 01/11/1973 | 1 | 088043153|1 |xx12#yahoo.com |
| 2 | Peter | 01/11/1973 | 1 | 088043153|2 |dsdsa#gmail.com |
| 2 | Peter | 01/11/1973 | 2 | 090044313|1 |xx12#yahoo.com |
| 2 | Peter | 01/11/1973 | 2 | 090044313|2 |dsdsa#gmail.com |
| 4 | Jose | 05/02/2008 | 1 | 088043153|1 |sasaw1#sdas.com |
| 4 | Jose | 05/02/2008 | 1 | 088043153|2 |cvcvsd#wew.es |
| 4 | Jose | 05/02/2008 | 2 | 088043153|1 |sasaw1#sdas.com |
| 4 | Jose | 05/02/2008 | 2 | 088043153|2 |cvcvsd#wew.es |
+-----+-------+-------------+----------+----------+----------+----------------+
So the result that i will to present in a view is the next
+-----+-------+-------------+----------+----------+----------+----------------+
| ID | Name | Birtday_date| CELL_TYPE| NUMBER |MAIL_TYPE|Email |
+-----+-------+-------------+----------+----------+----------+----------------+
| 1 | Byron | 12/10/1998 | 3 | 099141021|1 |jdoe#aol.com |
| 1 | Byron | 12/10/1998 | | |2 |jdoe1#aol.com |
| 1 | Byron | 12/10/1998 | 2 | 099091925| | |
| 1 | Byron | 12/10/1998 | 1 | 098041013| | |
| 2 | Peter | 01/11/1973 | 1 | 088043153|1 |xx12#yahoo.com |
| 2 | Peter | 01/11/1973 | | |2 |dsdsa#gmail.com |
| 2 | Peter | 01/11/1973 | 2 | 090044313| | |
| 4 | Jose | 05/02/2008 | 1 | 092049013|1 |sasaw1#sdas.com |
| 4 | Jose | 05/02/2008 | | |2 |cvcvsd#wew.es |
| 4 | Jose | 05/02/2008 | 2 | 098090233| | |
+-----+-------+-------------+----------+----------+----------+----------------+
I tried to achieve a similar output using
case
when row_number() over (partition by table1.id order by table2.type) = 1
then table1.value
end
as "VALUE"
But the result is nothing that I expect and some rows they repeats
What you need to do is enumerate the rows and then join on those enumerations. This is tricky, because you don't know how many are in each list. Well, there is another method using conditional aggregation:
select p.id, p.name, p.birthday,
max(cell_type) as cell_type, max(number) as number,
max(mail_type) as mail_type, max(email) as email
from person p left join
((select id_person, cell_type, number,
null as mail_type, null as email,
row_number() over (partition by id_person order by number) as seqnum
from phones
) union all
(select id_person, null as cell_type, null as number,
mail_type, email,
row_number() over (partition by id_person order by email) as seqnum
from emails
)
) pe
on pe.id_person = p.id_person
group by p.id, p.name, p.birthday, pe.seqnum
Hope this helps.
Create table person(ID int ,Name varchar(20), Birtday_date date)
Insert into person values
(1,'Byron' ,'12/10/1998'),
(2,'Peter' ,'01/11/1973'),
(4,'Jose ' ,'05/02/2008')
Create table phones (ID int,ID_Person int,CELL_TYPE int,NUMBER float)
Insert into phones values
(1221, 1 , 3,099141021),
(2221, 1 , 2,099091925),
(3222, 1 , 1,098041013),
(4321, 2 , 1,088043153),
(4561, 2 , 2,090044313),
(5678, 4 , 1,092049013),
(8990, 4 , 2,098090233)
Create table emails(ID int,ID_Person int, MAIL_TYPE int, Email varchar(100))
Insert into emails values
(221, 1 , 1, 'jdoe#aol.com '),
(222, 1 , 2, 'jdoe1#aol.com '),
(421, 2 , 1, 'xx12#yahoo.com '),
(451, 2 , 2, 'dsdsa#gmail.com'),
(578, 4 , 1, 'sasaw1#sdas.com'),
(899, 4 , 2, 'cvcvsd#wew.es ')
select p.id, p.name, p.Birtday_date,
case when Lag(number) over(partition by p.id order by p.id,pe.id) = number then null else cell_type end as cell_type,
case when Lag(number) over(partition by p.id order by p.id,pe.id) = number then null else number end as number,
mail_type as mail_type, email as email
from person p left join
(select pp.ID_Person, cell_type, number, mail_type, email,pp.id from
(select ID_Person, cell_type, number,id,
row_number() over (partition by ID_Person order by id ) as seqnum
from phones
) pp left join
(select ID_Person,
mail_type, email, 1 as seqnum
from emails
)e on pp.ID_Person = e.ID_Person and pp.seqnum = e.seqnum
) pe
on pe.ID_Person = p.Id
order by p.id, pe.id

How to (recursively) update a table based on available hierarchy?

Given these 3 column values, how can i update a table with the top level head for each employee?
| EmpID | EmpName | SupervisorID | DeptHeadID |
|:-----:|:-------:|:------------:|:----------:|
| 3 | Adam | null | |
| 1 | Sam | 5 | |
| 6 | Mike | 2 | |
| 5 | Jack | 3 | |
| 2 | Steph | 5 | |
| 8 | Rob | 2 | |
The result should be like this
| EmpID | EmpName | SupervisorID | DeptHeadID |
|:-----:|:-------:|:------------:|:----------:|
| 3 | Adam | null | null |
| 1 | Sam | 5 | 3 |
| 6 | Mike | 2 | 3 |
| 5 | Jack | 3 | 3 |
| 2 | Steph | 3 | 3 |
| 8 | Rob | 2 | 3 |
Example
;with cteP as (
Select EmpID,SupervisorID,TopLvl=EmpID
From YourTable
Where SupervisorID is null
Union All
Select r.EmpID,r.SupervisorID,TopLvl=p.TopLvl
From YourTable r
Join cteP p on r.SupervisorID = p.EmpID)
Update YourTable
set DeptHeadID = nullIf(TopLvl,A.EmpID)
From YourTable A
Join cteP B on A.EmpID=B.EmpID
-- Show Updated Table
Select * From YourTable
Updated Table
EmpID EmpName SupervisorID DeptHeadID
3 Adam NULL NULL
1 Sam 5 3
6 Mike 2 3
5 Jack 3 3
2 Steph 5 3
8 Rob 2 3