Oracle: Combining similar names together - sql

ItemNo Name Requested Qty
850045 MICHAEL 46 1045
850045 MICHAEL JACKSON 38 834
850045 LARRY SHEARIN 22 473
850045 Michael Jackson 11 233
850045 Larry 5 84
I have a table where Requester Name is not normalized. Michael and Michael Jack are the same person. Larry and Larry Shearin are also the same person. Is there a way to combine row data so that the Requested and Qty also sum up correctly? I was thinking there might be some sort of Oracle function or analytic that would do this...
ItemNo Name Requested Qty
850045 MICHAEL JACKSON 95 2112
850045 LARRY SHEARIN 27 557

There may be another way, but this should work using UPPER and matching any firstname (without spaces) to any fullname (with a space) -- if multiple full names match, you're results will be inaccurate.
SELECT T.ItemNo,
T.Name,
T.Requested + T2.Requested Requested,
T.Qty + T2.Qty Qty
FROM (
SELECT ItemNo, UPPER(Name) as Name, SUM(Requested) Requested, SUM(Qty) Qty
FROM YourTable
WHERE Name LIKE '% %'
GROUP BY ItemNo, UPPER(Name)
) T
JOIN (
SELECT ItemNo, UPPER(Name) as Name, SUM(Requested) Requested, SUM(Qty) Qty
FROM YourTable
WHERE Name NOT LIKE '% %'
GROUP BY ItemNo, UPPER(Name)
) T2 ON T.ItemNo = T2.ItemNo AND T.Name LIKE T2.Name||' %'
Here is the SQL Fiddle.
And here are the results:
ITEMNO NAME REQUESTED QTY
850045 MICHAEL JACKSON 95 2112
850045 LARRY SHEARIN 27 557
I assume you're total (32) for Larry was mistaken above (22 + 5)?
Hope this helps.

Related

Turning rows to columns in postgres

I have one table with rental contracts. (Postgres v10.18)
Like this:
Table Rental
Id Start Main_tenant_id Obect_id
101011 1.1.2021 1000 200
100222 1.1.2021 2050 210
If the Object has more than one Tenant the other ones a saved in a separate Table like this:
Table Rental_extra
Id rental_id xtra_tenant
20001 100222 3000
20002 100222 2700
20003 100222 2800
And i have a Person table like this:
Table Person
Id first_name last_name
1000 Peter Mcdonald
2050 Dan Hunt
3000 Steve Cole
2700 Ian Wright
2800 William Pears
Now i need to get this output:
Goal
Id tenant 1 tenant 2 tenant 3 tenant 4
101011 Peter Mcdonald null null null
100222 Dan Hunt Steve Cole Ian Wright William Pears
What's the best way? I tried with some crosstab example but couldn't make it work.
SELECT *
FROM crosstab(
$$
SELECT t.id, tenant_nr, concat_ws(' ', p.first_name, p.last_name)
FROM (
SELECT id, 0 AS tenant_nr, main_tenant_id AS tenant_id
FROM rental
UNION ALL
SELECT rental_id, row_number() OVER (PARTITION BY rental_id ORDER BY id), xtra_tenant
FROM extra_tenant
) t
JOIN person p ON p.id = t.tenant_id
ORDER BY 1 DESC, t.tenant_nr
$$
) AS goal(id int, tenant_1 text, tenant_2 text, tenant_3 text, tenant_4 text);
db<>fiddle here
Detailed explanation here:
PostgreSQL Crosstab Query
Postgres - Transpose Rows to Columns

Concatenate column values for specific fields while displaying other column values in Oracle 11.2

I am a SQL noob.
How can I concatenate column values for specific fields while displaying other column values?
I will try my best to show a simplified example.
Say I have the following table:
Table A
Name
Address
Email
Value1
Value2
Value3
Sam
123 Main Street
sam#coporate.com
34
51
39
Peter
789 High Street
peter#coporate.com
73
05
59
Sam
123 Main Street
sam#coporate.com
43
12
84
Sally
456 State Street
sally#coporate.com
35
76
23
Sally
456 State Street
sally#coporate.com
77
34
18
Peter
789 High Street
peter#coporate.com
32
14
54
Sally
456 State Street
sally#coporate.com
64
49
23
Expected output
Name
Address
Email
Value1
Value2
Value3
Sam
123 Main Street
sam#coporate.com
34,43
51,12
39,84
Sally
456 State Street
sally#coporate.com
35,64,77
76,49,34
23,23,18
Peter
789 High Street
peter#coporate.com
32,73
14,05
54,59
I tried using LISTAGG but the issue I had was that I was then not able to display the Name, Address and Email fields. Please help and thank you in advance!
Try:
SELECT NAME, ADDRESS, EMAIL,
LISTAGG(value1, ',') WITHIN GROUP (ORDER BY value1) new_value_1,
LISTAGG(value2, ',') WITHIN GROUP (ORDER BY value2) new_value_2,
LISTAGG(value3, ',') WITHIN GROUP (ORDER BY value3) new_value_3
FROM TABLE_A
GROUP BY NAME, ADDRESS, EMAIL;
I have my compiler into job computer, I am not sure. If I wrong, tell me to drop answer please.
This should do what you want:
select name, address, email,
listagg (value1, ',') within group (order by name) as values1,
listagg (value2, ',') within group (order by name) as values2,
listagg (value3, ',') within group (order by name) as values3
from a
group by name, address, email;
Here is a db<>fiddle.

order different columns into one order?

I have a table like this;
Student_Name1 mark1 Student_Name2 mark2
-------------- ------ --------------- --------
Kevin 77 Peter 78
Andrew 91 David 17
Scott 46 Bradley 28
How am i able to order mark1 and mark2 in the above table into descending order by including all the names and the points all together, like below?
Student_Name mark
-------------- ------
Andrew 91
Peter 78
Kevin 77
Scott 46
Bradley 28
David 17
I am using MSSQL Server 2008 R2
Use a UNION ALL:
Select Student_Name1 As Student_Name,
Mark1 As Mark
From YourTable
Union All
Select Student_Name2 As Student_Name,
Mark2 As Mark
From YourTable
Order By Mark Desc;
That's a strange table design but you can use UNION for this purpose like
select * from (
select Student_Name1 as Student_Name, mark1 as mark from student
union all
select Student_Name2 , mark2 from student ) xxx
order by mark desc;

query to find more than one name with different values

this is my table i need more than two names will appear as out put i used count in my query, but name timur has diff company so it cant count as 1 i need count as 2
Name ID Company Name CompanyID Role Name
Ahmed 73 King & Spalding 55 Counsel
Timur 78 Chance CIS Ltd 39 Partner
Timur 78 Clifford LLP 28 Counsel
Rahail 80 Reed Smith ltd 97 Partner
out put like this
Name ID Company Name CompanyID Role Name count
Ahmed 73 King & Spalding 55 Counsel 1
Timur 78 Chance CIS Ltd 39 Partner 2
Timur 78 Clifford LLP 28 Counsel 2
Rahail 80 Reed Smith ltd 97 Partner 1
I am assuming that name and ID match each other. So in case of duplicated names for different people, I am using ID for partitioning
SELECT
*,
count(*) over (partition by ID) as [count]
FROM yourtable
Use correlated sub-query:
select t.*, (select count(*) from tablename where name = t.name) as count
from tablename t
If you're using SQL Server 2005 or above then you can use a window function to achieve this easily:
SELECT
T.Name,
T.ID,
T.CompanyName,
T.CompanyID,
T.RoleName,
COUNT(*) OVER (PARTITION BY T.Name)
FROM
My_Table T

Using distinct and sum in sql server 2008

I'm trying to get the SUM(Values) for each Acct, but my issue is trying to get at least one entire row for a DISTINCT Acct with the SUM(Values).
I have some sample data for example:
Acct Values Name Street
123456789 100.20 John 66 Main Street
123456789 200.80 John 22 Main Avenue
222222222 50.25 Jane 1 Blvd
333333333 25.00 Joe 55 Test Ave
333333333 50.00 Joe 8 Douglas Road
555555555 75.00 Tim 12 Clark Ave
666666666 500.00 Tim 12 Clark Street
666666666 500.00 Tim 3 Main Rd.
My query consisted of:
SELECT DISTINCT Acct, SUM(Value) AS [TOTAL]
FROM TABLE_NAME
GROUP BY Acct
The above query gets me close to what I need, but I need the entire row.
Example below of what I am looking for:
Acct Total Name Addr1
123456789 301.00 John 66 Main Street
222222222 50.25 Jane 1 Blvd
333333333 75.00 Joe 55 Test Ave
555555555 75.00 Tim 12 Clark Ave
666666666 1000.00 Tim 12 Clark Street
Thanks.
If it does not matter what address you return, then you can apply and aggregate to the other columns:
SELECT Acct,
SUM(Value) AS [TOTAL],
max(name) name,
max(Street) addr1
FROM TABLE_NAME
GROUP BY Acct;
See SQL Fiddle with Demo
You can do this using window functions such as row_number() in most databases:
select acct, total, name, addr1
from (select t.*, row_number() over (partition by acct order by acct) as seqnum,
sum(value) over (partition by acct) as Total
from table_name
) t
where seqnum = 1;
I would use Windowing Functions (the OVER clause) to solve this.
SELECT DISTINCT
Acct
,SUM([Values]) OVER (PARTITION BY Acct) AS 'Total'
,Name
,FIRST_VALUE(Street) OVER (PARTITION BY Acct ORDER BY Street DESC) AS 'Addr1'
FROM TABLE_NAME
;
The nice thing about Windowing Functions is that you do not add things to a grouping that you do not need in your functions (e.g. SUM), instead you can focus on describing what you are looking for.
In the SQL above, we are saying we want the SUM of Values grouped by (or PARTITION BY as it is called in the OVER clause) Acct. The FIRST_VALUE allows use to return the first value of the street address. The same did not have a DATETIME column so it is hard to say what the order should be for the first value. There is also a LAST_VALUE windowing function. Assuming you do have a DATETIME column you would want to ORDER BY that column value, if not you can just pick some value like I did with Street (MAX might also be a good option then too, but having some type of DATETIME value would be the best way to do it).
Check out this SQL Fiddle: http://sqlfiddle.com/#!6/a474c/8
Here is the BOL about SUM using the OVER clause: http://msdn.microsoft.com/en-us/library/ms187810.aspx
Here is more info on FIRST_VALUE: http://blog.sqlauthority.com/2011/11/09/sql-server-introduction-to-first-_value-and-last_value-analytic-functions-introduced-in-sql-server-2012/
Here is a blog post I've done on the Windowing Functions: http://comp-phil.blogspot.com/2013/03/higher-order-functions.html