I'm stuck with an easy SQL Server thing for my own personal project.
I have a table X:
| Name | Lecture | Points |
|:-----------|------------:|:------------:|
| John | Math | 2
| John | Bio | 5
| Tom | Physics | 8
| Tom | Math | 2
| Bob | Physics | 1
| Bob | Bio | 6
And I want to group by Name and to put all points I one row for each person:
| Name | Math | Bio | Physics |
|:-----------|------:|:----:|:-------:|
| John | 2 | 5 | NULL
| Tom | 2 | NULL | 8
| Bob | NULL | 6 | 1
I tried doing this:
SELECT Name, ? AS Math, ? AS Bio, ? AS Physics
FROM X
GROUP BY Name
but I don't know what to put instead of "?". How can I do that ?
You need a pivot table and you need to know the values, unless you want to use dynamic sql (not recommended unless absolutely necessary):
SELECT Name,
ISNULL([Math], 0) as [Math],
ISNULL([Bio], 0) as [Bio],
ISNULL([Physics], 0) as [Physics]
FROM
(
SELECT Name, Lecture, SUM(Points)
FROM Table X
GROUP BY Name, Lecture
) as t1
PIVOT (SUM([Points]) for [Lecture] in ([Math], [Bio], [Physics])) as t2
Related
TABLE 1: Data sent to vendor
| MemberID | FirstName | LastName | Etc |
| :------: | :-------: | :------: | :-: |
| 1 | John | Smith | Etc |
| 2 | Jane | Doe | Etc |
| 3 | Dan | Laren | Etc |
TABLE 2: Data returned from vendor
| MemberID | FirstName | LastName | Etc |
| :------: | :-------: | :------: | :-: |
| 1 | John | Smith | Etc |
| 2 | Jane | Doe | Etc |
| 3 | Dan | Laren | Etc |
We send data to a vendor which is used for their matching algorithm and they return the data with new information. The members are matched with a MemberID data element. How would I write a query which shows me which MemberIDs we sent to the vendor but the vendor didn't return?
NOT EXITS would be my first choice here.
Example
SELECT *
FROM Table1 A
WHERE NOT EXISTS (SELECT 1
FROM Table2 B
WHERE A.MemberID = B.MemberID )
SELECT MemberID
FROM Table1
WHERE MemberID NOT IN (SELECT MemberID FROM Table2)
Using EXCEPT is one option.
SELECT sent.[MemberID] FROM Tbl1_SentToVendor sent
EXCEPT
SELECT recv.[MemberID] FROM Tbl2_ReturnedFromVendor recv
This is just on MemberID, but the "EXCEPT" syntax can also support additional columns (e.g., in case you want to filter out data that may be the same as what you already have.)
Let's say I have the following table (data is completely fiction):
ID | MonthDate | PersonID | Name | Status | MonthsAgoSinceLastCheck
1 | 2017-12 | 900 | Jack | Ill | -
2 | 2018-01 | 900 | Jack | Ill | 1
3 | 2018-02 | 900 | Jack | Ill | 2
4 | 2018-03 | 900 | Jack | Healthy | 1
5 | 2017-02 | 901 | Bill | Ill | -
6 | 2017-03 | 901 | Bill | Ill | 1
7 | 2017-05 | 901 | Bill | Healthy | 1
For each record, I would like to see the previous status that person had X months ago since last check (column MonthsAgoSinceLastCheck). Notice that MonthDate can skip months.
So in this case, the result would be
ID | MonthDate | PersonID | Name | Status | MonthsAgoSinceLastCheck | PreviousSatus
1 | 2017-12 | 900 | Jack | Ill | - | -
2 | 2018-01 | 900 | Jack | Ill | 1 | Ill
3 | 2018-02 | 900 | Jack | Ill | 2 | Ill
4 | 2018-03 | 900 | Jack | Healthy | 1 | Ill
5 | 2017-02 | 901 | Bill | Healthy | - | -
6 | 2017-03 | 901 | Bill | Healthy | 1 | Healthy
7 | 2017-05 | 901 | Bill | Ill | 2 | Healthy
Any sugestions/tips? I tried to do this with CTE's and self-joins but failed on both.
It's way easier to use full dates than year and months separately. The first thing you should do is generate a full date from your year + month. Then just self join with previous month, depending on the last check.
;WITH DataWithDates AS
(
SELECT
T.ID,
MonthDate = CONVERT(DATE, T.MonthDate + '-01'),
T.PersonID,
T.Name,
T.Status,
T.MonthsAgoSinceLastCheck
FROM
YourTable AS T
)
SELECT
D.ID,
D.MonthDate,
D.PersonID,
D.Name,
D.Status,
D.MonthsAgoSinceLastCheck,
PreviousStatus = N.Status
FROM
DataWithDates AS D
LEFT JOIN DataWithDates AS N ON
D.PersonID = N.PersonID AND
N.MonthDate = DATEADD(MONTH, -1 * D.MonthsAgoSinceLastCheck, D.MonthDate)
I'm assuming your MonthDate has values for all rows, otherwise the conversion will fail. I'm also assuming that your - values for MonthsAgoSinceLastCheck are actually NULL.
try this:
select *,LAG(Status) OVER(Partition by Name Order by MonthDate,Id) AS PreviousSatus
from tab1
order by id
SQl Fiddle:http://sqlfiddle.com/#!18/04407/4
I need to take data from a table that looks like this:
name | server | instance | version | user
----------|----------|------------|----------|--------- -
package_a | x | 1 | 1 | AB
package_b | x | 1 | 1 | TL
package_a | x | 2 | 4 | SK
package_a | y | 1 | 2 | MD
package_c | y | 1 | 4 | SK
package_b | y | 2 | 1 | SK
package_a | y | 2 | 1 | TL
package_b | x | 2 | 3 | TL
package_c | x | 2 | 1 | TL
and I need to put it in a table like that:
name | v_x_1 | u_x_1 | v_x_2 | u_x_2 | v_y_1 | u_y_1 | v_y_2 | u_y_2
----------|-------|-------|-------|-------|-------|-------|-------|-------
package_a | 1 | AB | 4 | SK | 2 | MD | 1 | TL
package_b | 1 | TL | 3 | TL | NULL | NULL | 1 | SK
package_c | NULL | NULL | 1 | TL | 4 | SK | NULL | NULL
I already tried INSERT with (SUB)SELECT, tried to INSERT package names first using DISTINCT and UPDATE afterwards, played around with PIVOT and stuff like that.
But I'm rather new to SQL and programming in general, so I couldn't come up with a solution. Since I not only have a version number in the source table but also nvarchar columns, It seems like PIVOT won't be the way to go, right?
You can use PIVOT on a sub query that uses UNION to separate the user and version values.
insert into YourNewTable (name, [v_x_1],[u_x_1],[v_x_2],[u_x_2],[v_y_1],[u_y_1],[v_y_2],[u_y_2])
select *
from (
select name, cast([version] as varchar(30)) as value, concat('v_',[server],'_',instance) as title from YourTable
union all
select name, [user] as value, concat('u_',[server],'_',instance) as title from YourTable
) q
pivot (max(value) FOR title IN (
[v_x_1],[u_x_1],[v_x_2],[u_x_2],[v_y_1],[u_y_1],[v_y_2],[u_y_2]
)
) pvt;
I've found similar questions but nothing that has a solution I've been able to make work for me. I've been out of practice and stuck on this.
I have a table that tracks employee positions. Each employee can have any number of active positions. I want to display each employee as a single record with all their positions in that record spanning multiple columns.
A glance at the data shows that there are no employees with more than 6 active positions and since this is a one-time query, I should be able to work with that number.
The positions all have a sequence number assigned but they're not in a nice handy order - inactive positions for an employee retain the sequence number.
So right now I have something that looks like this:
ID | Name | Title | Cat | Seq
------------------------------
10 | John | Asst. | HR | 13
10 | John | Tutor | EDU | 17
11 | Sue | Mgr | PA | 6
11 | Sue | Adj. | EDU | 7
11 | Sue | Tutor | EDU | 13
...
11 | Sue | Asst. | HR | 22
But I want it to look like this:
ID | Name | Title 1 | Cat 1 | Title 2 | Cat 2 | Title 3...| Title 6 | Cat 6
----------------------------------------------------------------------------
10 | John | Asst. | HR | Tutor | EDU | NULL | NULL | NULL
11 | Sue | Mgr. | PA | Adj. | EDU | Tutor | Asst. | HR
Let me know what additional information I need to provide.
You can use a combination of row_number and pivots to do this. Using SQL Server 2012+ the query could look something like below. It's a bit messy, but it should get the job done, although there might be better ways to accomplish the same result.
select
id
, name
, max([Title 1]) as [Title 1]
, max([Cat 1]) as [Cat 1]
, max([Title 2]) as [Title 2]
, max([Cat 2]) as [Cat 2]
, max([Title 3]) as [Title 3]
, max([Cat 3]) as [Cat 3]
-- and so on for the remaining columns...
from (
select
id, name, title, cat
, t = concat('Title ',row_number() over (partition by id order by seq))
, c = concat('Cat ',row_number() over (partition by id order by seq))
from your_table
) src
pivot ( max(title) for t in ([title 1],[title 2],[title 3]) )pt
pivot ( max(cat) for c in ([cat 1],[cat 2],[cat 3]) )pc
group by id, name;
I only wrote out title/cat 1 through 3 to save some space but you should get the idea.
Sample SQL Fiddle
Sample result:
| id | name | Title 1 | Cat 1 | Title 2 | Cat 2 | Title 3 | Cat 3 |
|----|------|---------|-------|---------|-------|---------|--------|
| 10 | John | Asst. | HR | Tutor | EDU | (null) | (null) |
| 11 | Sue | Mgr | PA | Adj. | EDU | Tutor | EDU |
This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 8 years ago.
I'm pretty new to SQL Server so don't really know what I'm doing with this. I have two tables, which might look like this:
table 1
| ID | customer | Date |
| 1 | company1 | 01/08/2014 |
| 2 | company2 | 10/08/2014 |
| 3 | company3 | 25/08/2014 |
table 2
| ID | Status | Days |
| 1 | New | 6 |
| 1 | In Work | 25 |
| 2 | New | 17 |
| 3 | New | 14 |
| 3 | In Work | 72 |
| 3 | Complete | 25 |
What I need to do is join based on the ID, and create new columns to show how long each ID has been in each status. Every time an order goes to a new status, a new line is added and the number of days is counted as in the 2nd table above. What I need to create from this, should look like this:
| ID | customer | Date | New | In Work | Complete |
| 1 | company1 | 01/08/2014 | 6 | 25 | |
| 2 | company2 | 10/08/2014 | 17 | | |
| 3 | company3 | 25/08/2014 | 14 | 72 | 25 |
So what do I need to to to create this?
Thanks for any help, as I say I'm pretty new to this.
I would suggest that AHiggins' link is a better candidate to mark this as a dupe rather than the one that's actually been selected because his link involves a join.
WITH [TimeTable] AS (
SELECT
T1.ID,
T1.[Date],
T2.[Status] AS [Status],
T2.[Days]
FROM
dbo.Table1 T1
INNER JOIN dbo.Table2 T2
ON T2.ID = T1.ID
)
SELECT *
FROM
[TimeTable]
PIVOT (MAX([Days]) FOR [Status] IN ([New], [Complete], [In Work])) TT
;