SQL arrange row in column - sql

I have following SQL query:
SELECT
PatientMRN,
OrderDate,
PatientMRN,
OrdereName,
FROM OrderItem
For some MRN patient have many orders and I would like to have order related to each patient in a column rather than have duplicate row of same MRN with different order.
So instead of having:
MRN OrdereName
012 Name one
012 Name two
012 Name three
012 Name four
I want to have it as follow:
MRN OrdereName1 OrderName2 OrderName3
012 Name one Name two Name three
unfortunately it is a confidential DB so I can attach it here.

If you know in advance the maximum number of orders per patient, you can use window functions and conditional aggregation:
select patientmrn,
max(case when rn = 1 then orderename end) as orderename1,
max(case when rn = 2 then orderename end) as orderename2,
max(case when rn = 3 then orderename end) as orderename3
from (
select t.*, row_number() over(partition by patientmrn order by orderename) rn
from mytable t
) t
group by patientmrn
You can expand the select clause with more conditional max() as needed (additional columns show null values when there is no more orders to display).
You control how orders are spread in the columns using the order by clause of the row_number(). Here, orders are orderes by ascending name. If, for example, you wanted to order them by date, you would change the order by clause to order by orderdate.

Related

Transposing a column of data in SQL

In SQL my data output is
Agreement ID
ProductStatus
125
A
125
C
125
N
I want to see this instead as
Agreement ID
ProductStatus
125
A,C, N
OR
Agreement ID
ProductStatus1
ProductStatus2
ProductStatus3
125
A
C
N
I've tried a few simple pivots, but the values a, c & n CAN be different and random values each time.
Can anyone help?
You can use a group_concat function. Your query will be something like this
SELECT agreement_id, group_concat(Product_Status)
FrOM mytable
group by agreement_id
This is for MySQL, for other databases you can search for group_concat alternative function for that particular database.
Seems like you are new to database. You can use this reference to learn more.
https://www.mysqltutorial.org/basic-mysql-tutorial.aspx
If you can get three values in different columns using conditional aggregation:
select agreementid,
max(case when seqnum = 1 then ProductStatus end) as ProductStatus_1,
max(case when seqnum = 2 then ProductStatus end) as ProductStatus_2,
max(case when seqnum = 3 then ProductStatus end) as ProductStatus_3
from (select t.*,
row_number() over (partition by agreementid order by agreementid) as seqnum
from t
) t
group by agreementid;
The SQL standard for creating a list is:
select agreementid,
list_agg(ProductStatus, ',') within group (order by productstatus) as productstatuses
from t
group by agreementid;
Many databases have different names for this function.
In both of these cases, the ordering of the columns or elements of the list are indeterminate. SQL table represent unordered sets (well, technically multisets) so there is no ordering unless a column specifies the ordering.

Combining multiple rows for each unique ID as a single row with multiple indexed column names in a view in SQL Server

In MS SQL Server 2016, I have a view, vw_PERSON_COMPANY_CONTACT_INFO, with the following columns:
,[COMPANY_ID]
,[PERSON_ID]
,[PERSON_NAME]
,[TITLE]
,[ADDRESS_ID]
,[ADDRESS_LINE_1]
,[ADDRESS_LINE_2]
,[ADDRESS_LINE_3]
,[CITY]
,[PROVINCE_STATE]
,[COUNTRY]
,[POSTAL_CODE]
,[EMAIL_ID]
,[EMAIL_ADDRESS]
,[PHONE_ID]
,[PHONE_NUMBER]
,[EXT]
Each row represents personal and contact information for individual employees. Some companies can have only a single employee, other a few dozens.
I would like to be able to create another view, vw_COMPANY_CONTACTS, combining all person/contact information (everything except COMPANY_ID, which would be shared by all entries in the row) as a single row per unique COMPANY_ID for the first 7 employees found. Each column name would potentially be renamed and incremented by an index starting with 1. As an example, I would have ADDRESS_LINE_1 As [Address1a] for the first employee, As [Address2a] for the second, As [Address3a] for the third, etc.
What would be the most efficient way to create such view?
You can use rown_number() and conditional aggregation.
The logic is like:
create view vw_COMPANY_CONTACTS as
select
company_id,
max(case when rn = 1 then person_id end) person_id_1,
max(case when rn = 1 then title end) title_1,
-- other columns for the contact n°1 go here
max(case when rn = 2 then person_id end) person_id_2,
max(case when rn = 2 then title end) title_2,
-- other columns for the contact n°2 go here
from (
select t.*, row_number() over(partition by company_id order by person_id) rn
from vw_PERSON_COMPANY_CONTACT_INFO t
) t
group by company_id

displaying distinct column value with corresponding column random 3 values

I have a table employee with columns (state_cd,emp_id,emp_name,ai_cd) how can i display disticnt state_cd with 3 different values from ai_cd
the answer should be
state_cd ai_cd
------- --------
TX 1
2
5
CA 9
10
11
This type of operation is normally better done in the application. But, you can do it in the query, if you really want to:
select (case when row_number() over (partition by state_cd order by ai_cd) = 1
then state_cd
end) as state_cd,
ai_cd
from employee e
order by e.state_cd, e.ai_cd;
The order by is very important, because SQL result sets are unordered. Your result requires ordering in order to make sense.
Just group by state_id and then count using count(Distinct column_name_)
select state_id from (select state_id,COUNT(DISTINCT ai_cd) as cnt from employee group by state_id) where cnt==3

How to do a Postgresql group aggregation: 2 fields using one to select the other

I have a table - Data - of rows, simplified, like so:
Name,Amount,Last,Date
A,16,31,1-Jan-2014
A,27,38,1-Feb-2014
A,12,34,1-Mar-2014
B,8,37,1-Jan-2014
B,3,38,1-Feb-2014
B,17,39,1-Mar-2014
I wish to group them similar to:
select Name,sum(Amount),aggr(Last),max(Date) from Data group by Name
For aggr(Last) I want the value of 'Last' from the row that contains max(Date)
So the result I want would be 2 rows
Name,Amount,Last,Date
A,55,34,1-Mar-2014
B,28,39,1-Mar-2014
i.e. in both cases, the value of Last is the one from the row that contained 1-Mar-2014
The query I'm actually doing is basically the same, but with many more sum() fields and millions of rows, so I'm guessing an aggregate function could avoid multiple extra requests each group of incoming rows.
Instead, use row_number() and conditional aggregation:
select Name, sum(Amount),
max(case when seqnum = 1 then Last end) as Last,
max(date)
from (select d.*, row_number() over (partition by name order by date desc) as seqnum
from data d
) d
group by Name;

SQL Query to obtain the maximum value for each unique value in another column

ID Sum Name
a 10 Joe
a 8 Mary
b 21 Kate
b 110 Casey
b 67 Pierce
What would you recommend as the best way to
obtain for each ID the name that corresponds to the largest sum (grouping by ID).
What I tried so far:
select ID, SUM(Sum) s, Name
from Table1
group by ID, Name
Order by SUM(Sum) DESC;
this will arrange the records into groups that have the highest sum first. Then I have to somehow flag those records and keep only those. Any tips or pointers? Thanks a lot
In the end I'd like to obtain:
a 10 Joe
b 110 Casey
You want the row_number() function:
select id, [sum], name
from (select t.*]
row_number() over (partition by id order by [sum] desc) as seqnum
from table1
) t
where seqnum = 1;
Your question is more confusing than it needs to be because you have a column called sum. You should avoid using SQL reserved words for identifiers.
The row_number() function assigns a sequential number to a group of rows, starting with 1. The group is defined by the partition by clause. In this case, all rows with the same id are in the same group. The ordering of the numbers is determined by the order by clause, so the one with the largest value of sum gets the value of 1.
If you might have duplicate maximum values and you want all of them, use the related function rank() or dense_rank().
select *
from
(
select *
,rn = row_number() over (partition by Id order by sum desc)
from table
)x
where x.rn=1
demo