Pivoting a single field in a table - sql-server

I have a table of the following structure:
Name
Type
Line
UniqueID
Key
Value
I need to select all the fields except UniqueID field and add a key 'UniqueID' and a Value field with the value of the UniqueID to the result set.
For example if I have three records:
Name Type Line UniqueID Key Value
___________________________________________________________________
John Doe Employee 2 test333 SSN 123-45-2345
John Doe Employee 3 test333 Address 555 Rodeo Drive
Jane Doe Visitor 2 test444 SSN 345-67-8907
my result set would need to be:
Name Type Line Key Value
___________________________________________________
John Doe Employee 2 UniqueID test333
John Doe Employee 2 SSN 123-45-2345
John Doe Emplyee 3 Address 555 Rodeo Drive
Jane Doe Visitor 2 UniqueID test444
Jane Doe Visitor 2 SSN 345-67-8907
Do I use pivots? Can anyone point me into the right direction?

This is kind of an odd request, at least to me. But anyhow, you can approach it a few ways. One way is to use cross apply:
select
name,
type,
line,
newkey,
newvalue
from
table1
cross apply
( values
('UniqueID',uniqueid),
('SSN',Value),
('Address',Value)
) c
(newkey,newvalue)
SQL Fiddle demo
Based on your comments, we'll chuck the union all method.
Here is an incredibly ugly and kludgy unpivot, combined with a union (to get the unique ids):
select
name,
type,
line,
newkey2,
newvalue
from
(select
name,
type,
line,
[key],
[value]
from table1) t1
unpivot
(
newvalue for newkey in ([Value])
) u
unpivot
(newkey2 for newvalue2 in ([key])) u2
union all
select
name,
type,
line,
'UniqueID',
Uniqueid
from
table1
Unpivot SQL Fiddle

Related

How do I return different entries which share the same ID in the same table?

I have a legacy table: Students in my database (SQL-Server) as below:
STUDENTID - SURNAME - FORENAME
DJ1 Doe John
DJ1 Doe John
DJ2 Doe Jane
DJ2 Doe Jane
DJ1 Dark Odin
AS1 Tom Layton
....
It is expected to have duplication in my table like in the case of John Doe or Jane Doe. I don't want that to be treated as a duplicate data. What I want to avoid is actually having different student sharing the same STUDENTID (e.g. Odin Dark and John Doe).
How do I create a query that return the student with different name sharing the same STUDENTID?
So My Query will return something like this:
ID - Surname - Forname
DJ1 Doe John
DJ1 Dark Odin
Thanks in advance.
Here you go. Not the prettiest query but it gets you the data you are looking for I think.
SELECT * FROM Students s
JOIN
(SELECT StudentID, Surname, Forename FROM Students
GROUP BY StudentID, Surname, Forename
HAVING COUNT(*) > 1) sub
ON sub.StudentID = s.StudentID
WHERE sub.Forename <> s.Forename and sub.Surname <> s.Surname and sub.StudentID = s.StudentID
different names with the same id can be found with this query. It will not show the duplicate records.
select distinct s1.*
from students s1
join students s2 on s1.studentid = s2.studentid and (s1.surname <> s2.surname or s1.forename <> s2.forename)

Left Join containing where clause INSIDE join

Lets say we have the following table structure:
DECLARE #Person TABLE
(
PersonId INT,
Name VARCHAR(50)
)
DECLARE #Address TABLE
(
AddressId INT IDENTITY(1,1),
PersonId INT
)
And we insert two person records:
INSERT INTO #Person (PersonId, Name) VALUES (1, 'John Doe')
INSERT INTO #Person (PersonId, Name) VALUES (2, 'Jane Doe')
But we only insert a address record for John
INSERT INTO #Address (PersonId) VALUES (1)
If I execute the following queries I get different results
SELECT *
FROM #Person p
LEFT JOIN #Address a
ON p.PersonId = a.PersonId AND a.PersonId IS NULL
PersonId | Name | AddressId | PersonId
1 | John Doe | NULL | NULL
2 | Jane Doe | NULL | NULL
VS
SELECT *
FROM #Person p
LEFT JOIN #Address a
ON p.PersonId = a.PersonId
WHERE a.PersonId IS NULL
PersonId | Name | AddressId | PersonId
2 | Jane Doe | NULL | NULL
Why are the queries returning different results?
The first query is not meeting any of your conditions. Hence it is displaying all results from the #Person table (Typical Left join). Where as in the second query, the where clause is applied after the join. Hence it is displaying proper result.
First:
get all records (two) from Person and join 0 records from Address, cos none of address have PersonID = NULL. After that no additional filters applyed. And you see two records from Person
Second:
get all records (two) from Person and one of them joined to Address with ID = 1. After that your WHERE filter applyed and one of records with joined ID = 1 disappears.
ON clause defines which all matching rows to show from both tables.
WHERE clause actually filters the rows.
In the 1st query, it is returning 2 rows because LEFT JOIN returns all the rows from the left table irrespective of match from right table.
2nd query is returning 1 row, because for PersonId=1, #Address table contains a matching record hence a.PersonId is NOT NULL.
Make it a habit to read your SQL query from the Where condition and then look at your joins, this will give you a clearer meaning/understanding of what is happening or going to be returned.
In this case you said WHERE a.PersonId IS NULL the Select Part must happen and It must Join using the following join criteria.
That is how your query is being read by your machine hence the different sets of results.
And then in contrast, on the condition where there is no where clause, the results on the Left table (p) do not have to exist on (a) but at the same time the results on (a) must be null but already they might not exist. Already at this point your SQL will be confused.

how to select a row based on a single distinct value

If i have 4 rows and want to select rows based on a single column's distinct values and dont mind which info it uses for the rest of the row, how do i do this? There doesn't seem to be a 'distinct' function for single cols whilst maintaining rest of row data.
eg
Name, value
john 1
john 2
michael 3
michael 5
result
john 1
michael 5
note it could have been john 2 or michael 3, i dont care which row for John or Michael it uses for the rest of the values.
GROUP BY Name and use any aggregate function with the value MIN or MAX since you don't care about the value of it:
SELECT Name, MIN(value)
FROM table
GROUP BY Name
Try this
select a.* from TAbleName a
inner join
(
select distinct name,min(Id) as id from TAbleName
group by name
) as b
on a.name= b.name
and a.id=b.id

UNION with dissimilar columns

TABLE A
ID Name Age
1 John 22
TABLE B
ID Name
5 Erik
I want result like
ID Name Age
1 John 22
5 Erik
When I am performing UNION giving error
"All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists."
How to get desired result?
You could supply a dummy column in lieu of the missing one that returns NULL as below.
SELECT ID,
Name,
Age
FROM TABLE_A
UNION ALL
SELECT ID,
Name,
NULL
FROM TABLE_B

Include NULL in each "Details Group" in SSRS

In SSRS I have a List with, say, a table with two columns: name and number e.g.:
NAME NUMBER
John 123
John 456
John NULL
Name is never null, but number may be. In this case I want the report to include the NULL in each group, like this:
GROUP 1:
John NULL
John 123
GROUP 2:
John NULL
John 456
The SSRS, however, puts the null in a group on its own. How do I accomplish this?
You have told SSRS to group on the NUMBER column, so it will generate a separate group for each value in the NUMBER column and then display those rows. To get what you want, you have to make the data set have the rows you want.
Select Name, Number, cast(Number as varchar(50)) as displayvalue
From mytable
UNION ALL
Select m.Name, m.Number, 'NULL' as displayvalue
From mytable m
Where exists(Select 1 from mytable where Name=m.Name and Number is NULL)
Group by Name, Number
Then group on the Number column but report on the DisplayValue column.

Resources