This question already has answers here:
TSQL Pivot without aggregate function
(9 answers)
Closed 4 years ago.
How can we retrieve information to be a row information from column values?
For example, we have a table
|-----------|-------------|--------------|
| ID | Field | FieldVlaue |
|-----------|-------------|--------------|
| 1 | Name | Jack |
|-----------|-------------|--------------|
| 1 | Country | Australia |
|-----------|-------------|--------------|
| 1 | PostCode| 0277 |
|-----------|-------------|--------------|
| 2 | Name | John |
|-----------|-------------|--------------|
| 2 | address | Wyard |
|-----------|-------------|--------------|
| 2 | ContactNum | 1234567 |
|-----------|-------------|--------------|
Based on the above table, how can we get a table like below
|-----------|-------------|--------------|-------------|---------|-----------|
| ID | Name | Country | PostCode |Address | ContactNum|
|-----------|-------------|--------------|-------------|---------|-----------|
| 1 | Jack | Australia | 0277 |Null | Null |
|-----------|-------------|--------------|-------------|---------|-----------|
| 2 | John | Null | Null | Wyard |1234567
|-----------|-------------|--------------|-------------|---------|-----------|
use condition aggregation
select id,
max(case when Field='Name' then FieldVlaue end) as Name,
max(case when Field='Country' then FieldVlaue end) as Country,
max(case when Field='PostCode' then FieldVlaue end) as PostCode,
max(case when Field='Address' then FieldVlaue end ) as Address,
max(case when Field='ContactNum' then FieldVlaue end) as ContactNum
from t
group by id
Related
I have a question on whether if I can avoid using a cursor.
I have a table with thousands of record like this:
Date | Name | StateData |
-----------+-------+-----------+
22-10-2019 | Tom | OPENED |
22-10-2019 | David | NULL |
22-10-2019 | Tom | NULL |
22-10-2019 | Brand | CLOSED |
22-10-2019 | Tom | NULL |
23-10-2019 | Brand | NULL |
22-10-2019 | Brand | OPENED |
22-10-2019 | Tom | OPENED |
22-10-2019 | Brand | OPENED |
22-10-2019 | Tom | CLOSED |
22-10-2019 | Brand | CLOSED |
What I'd like to achieve is a result, where I can see each name on just 1 row with counting how many times they had which State "StateData".
Date | Name | OPENED | CLOSED | UNUSED |
-----------+------+--------+--------+--------+
22-10-2019 | Tom | 2 | 1 | 2 |
22-10-2019 | David| 0 | 0 | 1 |
22-10-2019 | Brand| 2 | 2 | 1 |
I've tried a select like this
SELECT DISTINCT d.Name, d.[opened], d.[closed], d.[unused], StateData
FROM [dbo].[StateData] d
INNER JOIN (
SELECT DISTINCT Name, [opened], [closed], [unused]
FROM [dbo].[StateData]
GROUP BY Name, [opened], [closed], [unused]
) dp
ON dp.Name = d.Name
;
I know it can be done with creating stored procedure using CURSOR, but I'm not that experienced with cursor.
Use conditional aggregation:
select
Date,
Name,
SUM(CASE WHEN StateDAte = 'Opened' THEN 1 ELSE 0 END) Opened,
SUM(CASE WHEN StateDAte = 'Closed' THEN 1 ELSE 0 END) Closed,
SUM(CASE WHEN StateDAte IS NULL THEN 1 ELSE 0 END) Unused
from mytable
group by Date, Name
You can use sql pivot as follows
;with cte as (select date,name,isnull(statedate,'unused') statedate from mytable)
select p.* from cte
pivot
(count(statedate) for statedate in ([Opened],[Closed], [unused] )) as p
GMB and Kemal,
thanks,
I have tried this
SELECT [Date],
[Name],
COUNT(CASE StateData WHEN 'OPENED' THEN 1 END) AS OPENED,
COUNT(CASE StateData WHEN 'CLOSED' THEN 1 END) AS CLOSED,
COUNT(CASE WHEN StateData IS NULL THEN 1 END) AS UNUSED
FROM YourTable
GROUP BY [Date],
[Name];
but the result is not correct
Name | OPENED | CLOSED | UNUSED |
Tom | 2 | 0 | 57412 |
Brad | 2 | 0 | 57412 |
David | 2 | 0 | 57412 |
the correct result should be this
Date | Name | OPENED | CLOSED | UNUSED |
-----------+------+--------+--------+--------+
22-10-2019 | Tom | 2 | 1 | 2 |
22-10-2019 | David| 0 | 0 | 1 |
22-10-2019 | Brand| 2 | 2 | 1 |
but it seems like its just copy pasting the results.
There is a table: prov_dl
| ID | Code | Value |
+----+----------+-------+
| 2 | PRC | 0,1701|
| 2 | Stad | 3 |
Data is stored in this form, that is,
there are several entries by code
You need to pull the data in this form:
| ID | Stadya | Percent |
+----+----------+-----------+
| 2 | 3 | 0,1701 |
I try this:
select id,
case when code='Stad' then Value end Stadya,
case when code='PRC' then Value end Percent
from prov_dl
| ID | Stadya | Percent|
+----+----------+--------+
| 2 | | 0,1701 |
| 2 | 3 | |
use max()
select id,
max(case when code='Stad' then Value end) as Stadya,
max(case when code='PRC' then Value end) as Percent
from prov_dl group by id
I've used SQL for a while but wouldn't say I'm at an advanced level. I've tinkered with trying to figure this out myself to no avail.
I have two tables - Transaction and TransactionType:
| **TransactionID** | **Name** | **TransactionTypeID** |
| 1 | Tom | 1 |
| 2 | Jim | 1 |
| 3 | Mo | 2 |
| 4 | Tom | 3 |
| 5 | Sarah | 4 |
| 6 | Tom | 1 |
| 7 | Sarah | 1 |
| **TransactionTypeID** | **TransactionType** |
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
The Transaction.TransactionTypeID is a Forein Key linked TransactionType.TransactionTypeID field.
Here's what I'd like to achieve:
I'd like a query (this will be a stored procedure) that returns three columns:
Name - the value of the Transaction.Name column.
NumberOfTypeATransactions - the count of the number of all transactions of type 'A' for that person.
NumberOfNonTypeATransactions - the count of the number of all transactions that are NOT of type A for that person, i.e. all other transaction types.
So, using the above data as an example, the result set would be:
| **Name** | **NumberOfTypeATransactions** | **NumberOfNonTypeATransactions** |
| Tom | 2 | 1 |
| Jim | 1 | 0 |
| Mo | 0 | 1 |
| Sarah | 1 | 1 |
I might also need to return the results based on a date period (which will be based on a 'transaction date' column in the Transaction table but I haven't finalized this requirement yet.
Any help in how I can achieve this would be much appreciated. Apologies of the layout of the tables is a bit odd - haven't worked out how to format them properly yet.
This is just conditional aggregation with a join:
select t.name,
sum(case when tt.TransactionType = 'A' then 1 else 0 end) as num_As,
sum(case when tt.TransactionType <> 'A' then 1 else 0 end) as num_notAs
from transaction t join
transactiontype tt
on tt.TransactionTypeID = t.TransactionTypeID
group by t.name;
I have a set of data that represents how people ranked various traits. I am trying to Pivot the data by two columns however, the column data is contained under a single column with a separate column acting as a discriminator.
Here is the scenario. People were given a list of three traits and asked to rank them in order of importance to them. They were given two lists of three traits each and asked to rank each list 1 to 3, from most important to least important.
+----------+-------+----------------+---------------+------+
| RecordNo | Name | QuestionNumber | QuestionGroup | Rank |
+----------+-------+----------------+---------------+------+
| 1 | Bob | 1 | 1 | 2 |
| 2 | Bob | 2 | 1 | 1 |
| 3 | Bob | 3 | 1 | 3 |
| 4 | Bob | 1 | 2 | 1 |
| 5 | Bob | 2 | 2 | 2 |
| 6 | Bob | 3 | 2 | 3 |
| 7 | Sally | 1 | 1 | 3 |
| 8 | Sally | 2 | 1 | 2 |
| 9 | Sally | 3 | 1 | 1 |
| 10 | Sally | 1 | 2 | 1 |
| 11 | Sally | 2 | 2 | 3 |
| 12 | Sally | 3 | 2 | 2 |
+----------+-------+----------------+---------------+------+
What I would like to end up with is a PIVOT of the data so it looks like this ..
+----------+-------+-----------+-----------+-----------+------------+------------+------------+
| RecordNo | Name | Question1 | Question2 | Question3 | Question 1 | Question 2 | Question 3 |
| | | Group 1 | Group 1 | Group 1 | Group 2 | Group 2 | Group 2 |
+----------+-------+-----------+-----------+-----------+------------+------------+------------+
| 1 | Bob | 2 | 1 | 3 | 1 | 2 | 3 |
| 2 | Sally | 3 | 2 | 1 | 1 | 3 | 2 |
+----------+-------+-----------+-----------+-----------+------------+------------+------------+
I know how to do a Pivot on multiple columns great article on it here but what I cannot figure out is how to Pivot when the data is in the same column (QuestionNumber) separated by a discriminator column (QuestionGroup).
I also created an online table here
I think the simplest method for pivoting is conditional aggregation:
select name,
max(case when questiongroup = 1 and questionnumber = 1 then rank end) as q_1_1,
max(case when questiongroup = 1 and questionnumber = 2 then rank end) as q_1_2,
max(case when questiongroup = 1 and questionnumber = 3 then rank end) as q_1_3,
max(case when questiongroup = 2 and questionnumber = 1 then rank end) as q_2_1,
max(case when questiongroup = 2 and questionnumber = 2 then rank end) as q_2_2,
max(case when questiongroup = 2 and questionnumber = 3 then rank end) as q_2_3
from t
group by name;
I have a table with 10 milestones in the column milestone. The column milestone_achieved has either the value OK or NULL.
The name column has just names, whenever someone new enters, all the milestones are entered in the database with NULL.
Here is what a typical table looks like:
+------+-----------+--------------------+
| name | milestone | milestone_achieved |
+------+-----------+--------------------+
| John | 1 | OK |
| John | 2 | OK |
| John | 3 | NULL |
| John | 4 | NULL |
| John | 5 | NULL |
| John | 6 | NULL |
| Mary | 1 | OK |
| Mary | 2 | OK |
| Mary | 3 | OK |
| Mary | 4 | OK |
| Mary | 5 | OK |
| Mary | 6 | OK |
| Tim | 1 | NULL |
| Tim | 2 | NULL |
| Tim | 3 | NULL |
| Tim | 4 | NULL |
| Tim | 5 | NULL |
| Tim | 6 | NULL |
+------+-----------+--------------------+
Now I want the SQL query to return:
+------+-----------+--------------------+
| name | milestone | milestone_achieved |
+------+-----------+--------------------+
| John | 2 | OK |
| Mary | 6 | OK |
| Tim | 1 | NULL |
+------+-----------+--------------------+
My query right now looks like this:
SELECT name, MAX(milestone) FROM table HAVING milestone_achieved = 'OK' GROUP BY name
UNION ALL
SELECT name, MIN(milestone) FROM table HAVING milestone_achieved IS NULL AND MIN(milestone) = 1 GROUP BY name
This works in 90% of the cases, the problem occurs when e.g. milestone 1 and 2 was completed, but then milestone 1 was "uncompleted" because it didn't fit the specific criteria or whatever (imagine an assembly line where cars are assembled and a screw =milestone 1 isn't tight enough but the paint =milestone 2 is already on it or whatever else you can imagine, I have terrible imagination).
I am now looking fo a way to properly display those 10% cases.
One method is:
SELECT name, MAX(milestone)
FROM table
WHERE milestone_achieved = 'OK'
GROUP BY name
UNION ALL
SELECT name, MIN(milestone)
FROM table
GROUP BY name
HAVING MIN(milestone_achieved) IS NULL;
This follows the structure of your logic. You can do this with one SELECT:
SELECT name,
COALESCE(MAX(CASE WHEN milestone_achieved = 'OK' THEN milestone END),
MIN(milestone)
)
FROM table
GROUP BY name