Find T-SQL to Transpose A Table By Chunks - sql-server

I am looking for the cleanest, shortest, simplest, and most efficient way to do this using T-SQL. I hope that a single way is all of those things, but I realize that it may not be.
I have tried (unsuccessfully) using PIVOT, but what I think I need is to PIVOT by chunks AND without aggregating
I queried a large table to obtain this result:
(the result is ordered by year by the Number descending. the Number is the Number of occurrences of people born with that Name in the given year)
Name Number Year
John 9655 1880
William 9532 1880
James 5927 1880
Charles 5348 1880
George 5126 1880
John 8769 1881
William 8524 1881
Charles 5442 1881
George 4664 1881
James 4636 1881
John 9557 1882
James 9298 1882
William 5892 1882
George 5193 1882
Charles 5092 1882
I want to turn the above result into this:
1880 1881 1882
John John John
William William James
James Charles William
Charles George George
George James Charles

You can use PIVOT to get the result, the only thing that you will need to do is add a row_number() that is generated by partitioning the data by year ordered by the number. This unique sequence then allows you to return multiple rows for each year when you apply the aggregate function. Also since you want to convert string data you need to use either the max or min aggregate function:
select [1880], [1881], [1882]
from
(
select name, year,
row_number() over(partition by year
order by number desc) seq
from yourtable
) d
pivot
(
max(name)
for year in ([1880], [1881], [1882])
) p;
See SQL Fiddle with Demo. Returns:
| 1880 | 1881 | 1882 |
|---------|---------|---------|
| John | John | John |
| William | William | James |
| James | Charles | William |
| Charles | George | George |
| George | James | Charles |

Related

SQL name string matching -sql server

I have a table with data in the form
Date Amount Payer
04/01/2021 50 LARRY BURNS
16/01/2021 46 JOHN SMITH
15/01/2021 35 SUSAN ARTHUR
14/01/2021 28 S. ARTHUR
13/01/2021 21 JO SMITH
12/01/2021 13 LARRY BURNS
11/01/2021 6 SUSAN ARTHUR
I also have another table with data in the form
ID Customer Name Customer Type
10001 LARRY BURNS CU
10002 JOHN SMITH CU
10003 SUSAN ARTHUR CU
The first table which is a transactions table does not have a foreign key to reference the ID from the customer. The only information provided is the Payer column which includes inconsistently spelled names of customers. Is it possible to do some form of 'name matching' as a pseudo-join to allow retrieval of the customer name and ID?
Ideally in the form:
Date Amount Payer Customer Name ID
04/01/2021 50 LARRY BURNS LARRY BURNS 10001
16/01/2021 46 JOHN SMITH JOHN SMITH 10002
15/01/2021 35 SUSAN ARTHUR SUSAN ARTHUR 10003
14/01/2021 28 S. ARTHUR SUSAN ARTHUR 10003
13/01/2021 21 JO SMITH JOHN SMITH 10002
12/01/2021 13 LARRY BURNS LARRY BURNS 10001
11/01/2021 6 SUSAN ARTHUR SUSAN ARTHUR 10003
Given that you're willing to have an allowance for differences, you could try something like the following:
DECLARE #Payer table (
[Date] date, Amount decimal(18,2), Payer varchar(50)
);
INSERT INTO #Payer VALUES
( '01/04/2021', 50, 'LARRY BURNS' ),
( '01/16/2021', 46, 'JOHN SMITH' ),
( '01/15/2021', 35, 'SUSAN ARTHUR' ),
( '01/14/2021', 28, 'S. ARTHUR' ),
( '01/13/2021', 21, 'JO SMITH' ),
( '01/12/2021', 13, 'LARRY BURNS' ),
( '01/11/2021', 6 , 'SUSAN ARTHUR' );
DECLARE #Customer table (
ID int, CustomerName varchar(50), CustomerType varchar(2)
);
INSERT INTO #Customer VALUES
( 10001, 'LARRY BURNS', 'CU' ),
( 10002, 'JOHN SMITH', 'CU' ),
( 10003, 'SUSAN ARTHUR', 'CU' );
SELECT
[Date],
Amount,
Payer,
ID,
CustomerName
FROM #Payer AS payer
OUTER APPLY (
SELECT TOP 1
ID,
CustomerName
FROM #Customer AS c
WHERE
c.CustomerName = payer.Payer
OR
DIFFERENCE ( payer.Payer, c.CustomerName ) >= 3
OR
DIFFERENCE ( c.CustomerName, payer.Payer ) >= 3
) AS customer;
Returns
+------------+--------+--------------+-------+--------------+
| Date | Amount | Payer | ID | CustomerName |
+------------+--------+--------------+-------+--------------+
| 2021-01-04 | 50.00 | LARRY BURNS | 10001 | LARRY BURNS |
| 2021-01-16 | 46.00 | JOHN SMITH | 10002 | JOHN SMITH |
| 2021-01-15 | 35.00 | SUSAN ARTHUR | 10003 | SUSAN ARTHUR |
| 2021-01-14 | 28.00 | S. ARTHUR | 10003 | SUSAN ARTHUR |
| 2021-01-13 | 21.00 | JO SMITH | 10002 | JOHN SMITH |
| 2021-01-12 | 13.00 | LARRY BURNS | 10001 | LARRY BURNS |
| 2021-01-11 | 6.00 | SUSAN ARTHUR | 10003 | SUSAN ARTHUR |
+------------+--------+--------------+-------+--------------+

SQL to sort the data on multiple columns and add a column to assign an incremental counter for each sort combination

I have this as input data
CustomerId Customer_name PurchaseId Purchase_Date
----------------------------------------------------
1234 Robert Benson ABC123 12/07/2012
1218 Gary Thomas PP122 26/01/2013
1218 Gary Thomas PP122 28/01/2013
1234 Robert Benson ABC123 28/01/2013
1234 Robert Benson ABC123 29/01/2013
1254 Robert Sharma PML563 29/04/2012
1218 Gary Thomas PR124 06/03/2013
1234 Benson Cruiso LML123 14/07/2012
1234 Martha Cruiso FMPL123 15/07/2012
I want to sort the data on multiple columns i.e CustomerId and PurchaseId and add an order of the sorted data as
GroupID CustomerId Customer_name PurchaseId Purchase_Date
-------------------------------------------------------------
1 1218 Gary Thomas PR124 06/03/2013
1 1218 Gary Thomas PP122 26/01/2013
2 1218 Gary Thomas PP122 28/01/2013
1 1234 Robert Benson ABC123 12/07/2012
2 1234 Robert Benson ABC123 28/01/2013
2 1234 Robert Benson PP122 29/01/2013
1 1234 Benson Cruiso LML123 14/07/2012
1 1234 Martha Cruiso FMPL123 15/07/2012
1 1254 Robert Sharma PML563 27/04/2012
If I understand your question correctly, this can be achieved with a simple row_number or rank, depending on how you want your query to handle ties.
Select Row_Number() over
(partition by CustomerID, PurchaseID
order by PurchaseDate) as GroupID, *
from MyTable
This will assign sequential numbers to rows that have the same CustomerID and PurchaseID, assigning 1 to the first PurchaseDate, 2 to the next, and so on, and starting the numbering over again when it reaches a new CustomerID/PurchaseID combination. In the event of two rows with the same CustomerID, PurchaseID, and PurchaseDate, it will arbitrarily assign different numbers. If you want those cases to be treated as ties and assigned the same number, use rank or dense_rank instead of row_number.

SQL Server: Parent id with the least number of children

I have two tables Client and Instructor.
Client table :
id_client|name_client|FK_instructor
---------+-----------+------------
1 | Clinton | 2
2 | Gates` | 1
3 | Bush | 1
4 | Clinton | 2
5 | Obama | 1
6 | Jack | 3
Instructor table :
id_instructor|name_instructor
-------------+---------------
1 | Sara
2 | Sam
3 | Dean
4 | Julie
5 | Jake
I want to select the 3 instructors who have the least number of clients associated.
Thank you in advance.
Now that you mentioned you're using SQL Server, in addition to the GROUP BY and ORDER BY you need a TOP(3) on your SELECT.
SELECT TOP(3) i.id_instructor, i.name_instructor
FROM Instructor i
JOIN Client c ON c.FK_instructor = i.id_instructor
GROUP BY i.id_instructor, i.name_instructor
ORDER BY COUNT(*) --Implicitly ascending
Note that I added the instructor id to the group by compared to the other answer in case more than one instructor has the same name.
If you are working with Netezza, you could try:
SELECT name_instructor, COUNT(id_client)
FROM instructor_table
JOIN client_table on instructor_table.id_instructor = client_table.FK_instructor
GROUP BY name_instructor
ORDER BY COUNT(id_client) DESC
LIMIT 3
There is great documentation for Netezza here:
http://www-304.ibm.com/support/knowledgecenter/SSULQD_7.2.0/com.ibm.nz.dbu.doc/c_dbuser_sql_grammar.html
There are also SQL tutorials here:
http://www.w3schools.com/sql/

Constraints on database

I have a following table called students. If I want to put a constraint -- for each state, there are no more than 2 students can come from this same state, how could I express such a constraint in relational algebra?
name | hometown | gender
-----------------------------------
Bob | NYC | male
Alice | Washington D.C| female
Linda | London | female
Peter | Miami | male
Amy | Philadelphia | female
Lucy | NYC | female
James | Albany | male
Jason | Los Angeles | male
Cindy | Salt Lake City| female
Jackson| Princeton | male
Judy | Seattle | female
Marcia | San Francisco | female
Steve | NYC | male
John | Miami | male
You're going to need a relation providing the state for each town. Join that with this table (on town) and that will give you the state. Then group that result by state and count the occurrences, constraining the count to be less than or equal to two. As you haven't provided the required relation or relation names, I can't give you the algebra, but you should find this helps you get your homework done.

Select Same Customer Name but that has different customer Address

Trying to select records that are all for the same customer, but where the address is different.
So I can later let the user choose Bob Yonkers, then choose to update all of Bob's records to a specific address. So I want to show all the available records.
Data Example:
CUSTOMER_NAME, CUSTOMER_ADDRESS
Bob Yonkers , 42 Satellite Cir
Bob Yonkers , 667 Orbit St
Bob Yonkers , 42 Satellite Cir
Bob Yonkers , 667 Orbit St
David Boom , 5959 Bush Ave
David Boom , 5959 Bush Ave
David Boom , 5959 Bush Ave
David Boom , 5959 Bush Ave
David Boom , 5959 Bush Ave
Ruby Tuesday , 123 Highway Ln Apt#1
Ruby Tuesday , 123 Highway Ln
David Boom ,5959 Bush Ave
David Boom ,5959 Bush Ave
David Boom ,5959 Bush Ave
So the query would bring back these results...
Result Example:
CUSTOMER_NAME, CUSTOMER_ADDRESS
Bob Yonkers , 42 Satellite Cir
Bob Yonkers , 667 Orbit St
Ruby Tuesday , 123 Highway Ln Apt#1
Ruby Tuesday , 123 Highway Ln
Any help would be appreciated.
SELECT *
FROM [table] t1
INNER JOIN [table] t2 ON t1.Name=t2.Name AND t1.Address<>t2.Address
This is a refinement of Joel's:
SELECT distinct t1.*
FROM [table] t1
INNER JOIN [table] t2 ON t1.Name=t2.Name AND t1.Address<>t2.Address
give this a try...
select * from (select count(customername) as ct, customername, address from table group by customername, address) t1
where t1.ct>1
This intrigued me since a friend had asked me something similar. The query below will solve the problem, albeit in-efficiently:
mysql> select DISTINCT CUSTOMER_NAME,CUSTOMER_ADDRESS from CUST_ADDR
where CUSTOMER_NAME in (select CUSTOMER_NAME from CUST_ADDR GROUP BY
CUSTOMER_NAME HAVING COUNT(DISTINCT CUSTOMER_ADDRESS) > 1 );
+---------------+----------------------+
| CUSTOMER_NAME | CUSTOMER_ADDRESS |
+---------------+----------------------+
| Bob Yonkers | 42 Satellite Cir |
| Bob Yonkers | 667 Orbit St |
| Ruby Tuesday | 123 Highway Ln Apt#1 |
| Ruby Tuesday | 123 Highway Ln |
+---------------+----------------------+
4 rows in set (0.01 sec)

Resources