Update/multiply a field based on a value in another field - sql-server

I am new to SQL and have the following issue I would like to solve. The table I would like to edit looks like this:
ID | ShopID | ProductID | PurchasePrice
1 | 1 | 111 | 1,00
2 | 2 | 111 | 1,40
3 | 3 | 111 | 1,30
4 | 1 | 222 | 2,00
5 | 2 | 222 | 2,50
6 | 3 | 222 | 2,90
7 | 1 | 333 | 3,00
8 | 2 | 333 | 3,80
9 | 3 | 333 | 3,90
ID (unique)
ShopID (3 different values, representing 3 different shops)
ProductID (refers to unique id of different table where more common product info is stored) the same value is available three times for every different ShopID
PurchasePrice (over time shops 2 and 3 have edited their pricing, it's a mess now)
The Value of PurchasePrice for ShopID 2 and 3 should be 10% higher than the PurchasePrice for ShopID 1 where ProductID is the same. How can I easily do this in SQL server 2008?
The table should look like this:
ID | ShopID | ProductID | PurchasePrice
1 | 1 | 111 | 1,00
2 | 2 | 111 | 1,10
3 | 3 | 111 | 1,10
4 | 1 | 222 | 2,00
5 | 2 | 222 | 2,20
6 | 3 | 222 | 2,20
7 | 1 | 333 | 3,00
8 | 2 | 333 | 3,30
9 | 3 | 333 | 3,30

UPDATE t
SET t.PurchasePrice = p.PurchasePrice*1,10
FROM Table t
LEFT JOIN (
SELECT ProductID,PurchasePrice FROM Table WHERE ShopID=1) p ON t.ProductID = p.ProductID
WHERE t.ShopID<>1
Here we get the list of prices in Shop 1 (See the left join query) and update prices of shops other than 1 to shop 1's ProductPrice * 1,10

Related

SQL-Server Closure table query

I need a hierarchy for my database and decided to use the closure table model. The hierarchy tables have the usual structure, like this:
locations table
+----+---------+
| id | name |
+----+---------+
| 1 | Europe |
| 2 | France |
| 3 | Germany |
| 4 | Spain |
| 5 | Paris |
| 6 | Nizza |
| 7 | Berlin |
| 8 | Munich |
| 9 | Madrid |
+----+---------+
CREATE TABLE locations (
id int IDENTITY(1,1) PRIMARY KEY,
name varchar(30)
)
lacations_relation table
+----+--------+--------+-------+
| id | src_id | dst_id | depth |
+----+--------+--------+-------+
| 1 | 1 | 1 | 0 |
| 2 | 2 | 2 | 0 |
| 3 | 1 | 2 | 1 |
| 4 | 3 | 3 | 0 |
| 5 | 1 | 3 | 1 |
| 6 | 4 | 4 | 0 |
| 7 | 1 | 4 | 1 |
| 8 | 5 | 5 | 0 |
| 9 | 2 | 5 | 1 |
| 10 | 1 | 5 | 2 |
| 11 | 6 | 6 | 0 |
| 12 | 2 | 6 | 1 |
| 13 | 1 | 6 | 2 |
| 14 | 7 | 7 | 0 |
| 15 | 3 | 7 | 1 |
| 16 | 1 | 7 | 2 |
| 17 | 8 | 8 | 0 |
| 18 | 3 | 8 | 1 |
| 19 | 1 | 8 | 2 |
| 20 | 9 | 9 | 0 |
| 21 | 4 | 9 | 1 |
| 22 | 1 | 9 | 2 |
+----+--------+--------+-------+
CREATE TABLE locations_relation (
id int IDENTITY(1,1) PRIMARY KEY,
src_id int,
dst_id int,
depth int,
CONSTRAINT FK_src FOREIGN KEY (src_id)
REFERENCES locations (id),
CONSTRAINT FK_dst FOREIGN KEY (dst_id)
REFERENCES locations (id)
)
Now there is a third table, which holds information about documents and is referencing the locations table, which looks like this:
closure_junction
+----+------------+-------------+
| id | country_id | document_id |
+----+------------+-------------+
| 1 | 2 | 1 |
| 2 | 2 | 2 |
| 3 | 6 | 2 |
| 4 | 6 | 3 |
| 5 | 5 | 2 |
| 6 | 5 | 4 |
+----+------------+-------------+
CREATE TABLE closure_junction (
id int IDENTITY(1,1) PRIMARY KEY,
country_id int NOT NULL,
document_id int,
CONSTRAINT FK_countries FOREIGN KEY (id)
REFERENCES countries(id)
)
What I'd like to have is single SQL-Query which counts the document per location and if there are documents in a child it should be counted up in the parent. For example if paris holds 2 documents than france should automatically also hold 2 documents. The query should also output the path of each node to the root aswell as the depth of the node. I know there is way to do this recursively, but I'd like to avoid that.
I have a query which gives me the correct result, but I'm not satisfied with how it works. Is there a way to circumentvent storing the children in a column?
This is my query with the correct output:
;WITH cte (name, path, depth, children) AS
(
SELECT
node.name,
STRING_AGG(locations.name, ' / ' ) WITHIN GROUP (ORDER BY relation.depth DESC) as path,
MAX(relation.depth) as depth,
STRING_AGG(locations.id, ' ') as children
FROM locations node
INNER JOIN locations_relation relation
ON node.id = relation.dst_id
INNER JOIN locations
ON relation.src_id = locations.id
GROUP BY node.name
)
SELECT
name,
path,
depth,
COUNT(DISTINCT document_id) as count_docs
FROM cte
CROSS APPLY string_split(children, ' ')
LEFT JOIN closure_junction ON
closure_junction.country_id = value
GROUP BY name, path, depth
ORDER BY depth ASC
+---------+---------------------------+-------+------------+
| name | path | depth | count_docs |
+---------+---------------------------+-------+------------+
| Europe | Europe | 0 | 0 |
| France | Europe / France | 1 | 2 |
| Germany | Europe / Germany | 1 | 0 |
| Spain | Europe / Spain | 1 | 0 |
| Berlin | Europe / Germany / Berlin | 2 | 0 |
| Madrid | Europe / Spain / Madrid | 2 | 0 |
| Munich | Europe / Germany / Munich | 2 | 0 |
| Nizza | Europe / France / Nizza | 2 | 3 |
| Paris | Europe / France / Paris | 2 | 3 |
+---------+---------------------------+-------+------------+
Would be great if someone could give me a clue on how to accomplish this.
The count you can easily replace with a simple LEFT JOIN, but for this path you will still need to concatenate it somehow.
Something like this:
WITH CTE_path
AS
( SELECT node.id,
STRING_AGG(locations.name, ' / ' ) WITHIN GROUP (ORDER BY relation.depth DESC) as path
FROM locations node
INNER JOIN locations_relation relation
ON node.id = relation.dst_id
INNER JOIN locations
ON relation.src_id = locations.id
GROUP BY node.id)
SELECT l.name,count(DISTINCT cj.document_id),pa.path
FROM locations l
JOIN CTE_path pa
ON pa.id = l.id
LEFT JOIN locations_relation lr
ON l.id = lr.dst_id
LEFT JOIN closure_junction cj
ON cj.country_id = lr.src_id
GROUP BY l.name,pa.path

How can I get SQL results that resemble a pivot table

I am trying to get back some results from a database and it needs to be returned in a very specific way, similar to a pivot table but from what I've been reading about them I don't know if it applies since I do not need an aggregate. This is to display RFQ information in a report. The database structure is complicated but I will use a simplified example.
RFQ table
----------------
RFQID | Requestor
----------------
555 | 789
777 | 789
Item table
--------------------------
RFQID | Line | ItemID
--------------------------
555 | 1 | P07
777 | 1 | P07
ItemQuantity table
------------------------------------
RFQID | Line | Quantity | Unit
------------------------------------
555 | 1 | 5 | In
555 | 1 | 10 | In
555 | 1 | 15 | In
777 | 1 | 30 | In
777 | 1 | 50 | In
Vendor table
-----------------------------
RFQID | Line | VendorID
-----------------------------
555 | 1 | Speedy
777 | 1 | SlowPoke
So if I enter a query like this:
SELECT M.RFQID, Requester, I.Line, ItemID, Quantity, Unit, VendorID
FROM RFQ M
JOIN Item I ON M.RFQID = I.RFQID
JOIN Vendor V ON I.Line = V.Line AND I.RFQID = V.RFQID
JOIN ItemQuantity IQ ON IQ.Line = V.Line AND IQ.RFQID = V.RFQID
WHERE ItemID IN ('P07', 'P08')
ORDER BY M.RFQID DESC
Which will produce:
555 | 789 | 1 | P07 | 5 | In | Speedy
555 | 789 | 1 | P07 | 10 | In | Speedy
555 | 789 | 1 | P07 | 15 | In | Speedy
777 | 789 | 1 | P07 | 30 | In | SlowPoke
777 | 789 | 1 | P07 | 50 | In | SlowPoke
I need to get:
RFQID| Requestor | Line | ItemID | Quantity row1 | Unit row1 | Quantity row2 | Unit row2 | Quantity row3 | Unit row3 | VendorID
555 | 789 | 1 | P07 | 5 | In | 10 | In | 15 | In | Speedy
777 | 789 | 1 | P07 | 30 | In | 50 | In | NULL | NULL | SlowPoke
Is this possible? I know I can write a SP using a cursor but I wish to avoid that route if possible.
EDIT: This is part of a report that:
1) The whole company uses
2) Consists of 14 datasets
3) Is so customized that I doubt there is a report writer that can produce it.
4) It exists in Access 2003 which we wish to get rid of
5) I have almost the whole thing done with the PrintDocument with all the attributes table based so it can be modified without compiling anything.
Using Jason's technique I was able to produce the correct output.
SELECT M.RFQID, Requester, I.Line, ItemID, Qty1, Qty2, Qty3, VendorID
FROM RFQ M
JOIN Item I ON M.RFQID = I.RFQID
JOIN Vendor V ON I.Line = V.Line AND I.RFQID = V.RFQID
JOIN (SELECT RFQID, LineItem, MAX(CASE WHEN QtyID = 1 THEN QUANTITY END) AS Qty1, MAX(CASE WHEN QtyID = 2 THEN QUANTITY END) AS Qty2, MAX(CASE WHEN QtyID = 3 THEN QUANTITY END) AS Qty3
FROM ItemQuantity
GROUP BY RFQID, Line) IQ ON IQ.Line = I.Line AND IQ.RFQID = M.RFQID
WHERE ItemID IN ('P07', 'P08')
ORDER BY M.RFQID DESC
Which results in
RFQID| Requestor | Line | ItemID | Quantity row1 | Quantity row2 | Quantity row3 | VendorID
555 | 789 | 1 | P07 | 5 | 10 | 15 | Speedy
777 | 789 | 1 | P07 | 30 | 50 | NULL | SlowPoke
Although my demo data did not include a QtyID the table can be rewritten as:
ItemQuantity table
----------------------------------------------
RFQID | Line | QtyID | Quantity | Unit
----------------------------------------------
555 | 1 | 1 | 5 | In
555 | 1 | 2 | 10 | In
555 | 1 | 3 | 15 | In
777 | 1 | 1 | 30 | In
777 | 1 | 2 | 50 | In
The Unit can be added the same way.
Thanks Jason!

Create Tree Query From Numeric Mapping Table in SQL (Specific Format)

I have an exported table from accounting software like below.
AccountID AccountName
--------- -----------
11 Acc11
12 Acc12
13 Acc13
11/11 Acc11/11
11/12 Acc11/12
11/111 Acc11/111
11/11/001 Acc11/11/001
11/11/002 Acc11/11/002
12/111 Acc12/111
12/112 Acc12/112
I want to convert it to tree query in MS-SQL Server 2008 to use it as a Treelist datasource in my win aaplication.
I raised this question before and it's answered with a way that it was very very slow for my big table with more than 5000 records (Create Tree Query From Numeric Mapping Table in SQL). But I think counting "/" and separating AccountID field with "/" can solve my problem easier and very faster.
Anyway, My expected result must be like below:
AccountID AccountName ID ParentID Level HasChild
--------- ----------- --- --------- ------ --------
11 Acc11 1 Null 1 1
12 Acc12 2 Null 1 1
13 Acc13 3 Null 1 0
11/11 Acc11/11 4 1 2 1
11/12 Acc11/12 5 1 2 0
11/111 Acc11/111 6 1 2 0
11/11/001 Acc11/11/001 7 4 3 0
11/11/002 Acc11/11/002 8 4 3 0
12/111 Acc12/111 9 2 2 0
12/112 Acc12/112 10 2 2 0
Please Help Me.
I modified my answer given in the first question...
It would be best, if your table would keep the relation data directly in indexed columns. Before you change your table's structure you might try this:
A table with test data
DECLARE #tbl TABLE ( AccountID VARCHAR(100), AccountName VARCHAR(100));
INSERT INTO #tbl VALUES
('11','Acc11')
,('12','Acc12')
,('13','Acc13')
,('11/11','Acc11/11')
,('11/12','Acc11/12')
,('11/111','Acc11/111')
,('11/11/001','Acc11/11/001')
,('11/11/002','Acc11/11/002')
,('12/111','Acc12/111')
,('12/112','Acc12/112');
This will get the needed data into a newly created temp table called #tempHierarchy
SELECT AccountID
,AccountName
,ROW_NUMBER() OVER(ORDER BY LEN(AccountID)-LEN(REPLACE(AccountID,'/','')),AccountID) AS ID
,Extended.HierarchyLevel
,STUFF(
(
SELECT '/' + A.B.value('.','varchar(10)')
FROM Extended.IDsXML.nodes('/x[position() <= sql:column("HierarchyLevel")]') AS A(B)
FOR XML PATH('')
),1,2,'') AS ParentPath
,Extended.IDsXML.value('/x[sql:column("HierarchyLevel")+1][1]','varchar(10)') AS ownID
,Extended.IDsXML.value('/x[sql:column("HierarchyLevel")][1]','varchar(10)') AS ancestorID
INTO #tempHierarchy
FROM #tbl
CROSS APPLY(SELECT LEN(AccountID)-LEN(REPLACE(AccountID,'/','')) + 1 AS HierarchyLevel
,CAST('<x></x><x>' + REPLACE(AccountID,'/','</x><x>') + '</x>' AS XML) AS IDsXML) AS Extended
;
The intermediate result
+-----------+--------------+----+----------------+------------+-------+------------+
| AccountID | AccountName | ID | HierarchyLevel | ParentPath | ownID | ancestorID |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11 | Acc11 | 1 | 1 | | 11 | |
+-----------+--------------+----+----------------+------------+-------+------------+
| 12 | Acc12 | 2 | 1 | | 12 | |
+-----------+--------------+----+----------------+------------+-------+------------+
| 13 | Acc13 | 3 | 1 | | 13 | |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/11 | Acc11/11 | 4 | 2 | 11 | 11 | 11 |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/111 | Acc11/111 | 5 | 2 | 11 | 111 | 11 |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/12 | Acc11/12 | 6 | 2 | 11 | 12 | 11 |
+-----------+--------------+----+----------------+------------+-------+------------+
| 12/111 | Acc12/111 | 7 | 2 | 12 | 111 | 12 |
+-----------+--------------+----+----------------+------------+-------+------------+
| 12/112 | Acc12/112 | 8 | 2 | 12 | 112 | 12 |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/11/001 | Acc11/11/001 | 9 | 3 | 11/11 | 001 | 11 |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/11/002 | Acc11/11/002 | 10 | 3 | 11/11 | 002 | 11 |
+-----------+--------------+----+----------------+------------+-------+------------+
And now a similar recursive approach takes place as in my first answer. But - as it is using a real table now and all the string splitting has taken place already - it should be faster...
WITH RecursiveCTE AS
(
SELECT th.*
,CAST(NULL AS BIGINT) AS ParentID
,CASE WHEN EXISTS(SELECT 1 FROM #tempHierarchy AS x WHERE x.ParentPath=th.AccountID) THEN 1 ELSE 0 END AS HasChild
FROM #tempHierarchy AS th WHERE th.HierarchyLevel=1
UNION ALL
SELECT sa.AccountID
,sa.AccountName
,sa.ID
,sa.HierarchyLevel
,sa.ParentPath
,sa.ownID
,sa.ancestorID
,(SELECT x.ID FROM #tempHierarchy AS x WHERE x.AccountID=sa.ParentPath)
,CASE WHEN EXISTS(SELECT 1 FROM #tempHierarchy AS x WHERE x.ParentPath=sa.AccountID) THEN 1 ELSE 0 END AS HasChild
FROM RecursiveCTE AS r
INNER JOIN #tempHierarchy AS sa ON sa.HierarchyLevel=r.HierarchyLevel+1
AND r.AccountID=sa.ParentPath
)
SELECT r.AccountID
,r.AccountName
,r.ID
,r.ParentID
,r.HierarchyLevel
,r.HasChild
FROM RecursiveCTE AS r
ORDER BY HierarchyLevel,ParentID;
And finally I clean up
DROP TABLE #tempHierarchy;
And here's the final result
+-----------+--------------+----+----------+----------------+----------+
| AccountID | AccountName | ID | ParentID | HierarchyLevel | HasChild |
+-----------+--------------+----+----------+----------------+----------+
| 11 | Acc11 | 1 | NULL | 1 | 1 |
+-----------+--------------+----+----------+----------------+----------+
| 12 | Acc12 | 2 | NULL | 1 | 1 |
+-----------+--------------+----+----------+----------------+----------+
| 13 | Acc13 | 3 | NULL | 1 | 0 |
+-----------+--------------+----+----------+----------------+----------+
| 11/11 | Acc11/11 | 4 | 1 | 2 | 1 |
+-----------+--------------+----+----------+----------------+----------+
| 11/111 | Acc11/111 | 5 | 1 | 2 | 0 |
+-----------+--------------+----+----------+----------------+----------+
| 11/12 | Acc11/12 | 6 | 1 | 2 | 0 |
+-----------+--------------+----+----------+----------------+----------+
| 12/111 | Acc12/111 | 7 | 2 | 2 | 0 |
+-----------+--------------+----+----------+----------------+----------+
| 12/112 | Acc12/112 | 8 | 2 | 2 | 0 |
+-----------+--------------+----+----------+----------------+----------+
| 11/11/001 | Acc11/11/001 | 9 | 4 | 3 | 0 |
+-----------+--------------+----+----------+----------------+----------+
| 11/11/002 | Acc11/11/002 | 10 | 4 | 3 | 0 |
+-----------+--------------+----+----------+----------------+----------+

Need help based on conditions in SQL Server

I have a question about SQL Server.
Table patient:
pn | code | date | doctorcode
---------------------------------------
1 | 10 |2015-02-19 | 100
1 | 10 |2015-02-19 | 101
1 | 10 |2015-02-19 | 102
2 | 10 |2015-02-12 | 101
2 | 10 |2015-02-13 | 102
2 | 10 |2015-02-14 | 103
3 | 10 |2015-02-15 | 103
3 | 10 |2015-02-18 | 104
3 | 10 |2015-02-26 | 105
Table Patientref:
pn | code | sdate | edate | Status
-------------------------------------------------
1 | 10 |2015-02-13 | 2015-02-19 | 1
1 | 10 |2015-02-19 | 2015-03-24 | 2
1 | 10 |2015-04-28 | 2015-05-08 | 4
2 | 10 |2015-02-08 | 2015-02-19 | 4
2 | 10 |2015-02-09 | 2015-02-19 | 2
2 | 10 |2015-02-10 | 2015-02-19 | 2
2 | 10 |2015-02-11 | 2015-02-18 | 1
3 | 10 |2015-02-10 | 2015-02-17 | 4
3 | 10 |2015-02-10 | 2015-02-17 | 3
3 | 10 |2015-02-11 | 2015-02-18 | 3
2 | 10 |2015-04-10 | 2015-05-19 | 2
3 | 10 |2015-02-11 | 2015-02-18 | 1
3 | 10 |2015-02-26 | 2015-03-18 | 1
Here we need consider patient dates that fall between sdate and edate of the patientrefs table, and then we need to consider the highest status values in order (for example, the highest values in order - 2 is first highest, 4 is second highest, 3 is third highest, and 1 is fourth highest value)
If the date falls between multiple different sdate and edate with the same status values, then we need to consider the latest sdate value and from that entire record we need to extract that value.
Examples: patient
pn | code | date | doctorcode
2 | 10 |2015-02-12 | 101
2 | 10 |2015-02-13 | 102
2 | 10 |2015-02-14 | 103
Table : Patientref:
pn | code | sdate | edate | Status
2 | 10 |2015-02-08 | 2015-02-19 | 4
2 | 10 |2015-02-09 | 2015-02-19 | 2
2 | 10 |2015-02-10 | 2015-02-19 | 2
2 | 10 |2015-02-11 | 2015-02-18 | 1
Here, pn=2 values have dates which fall between sdate and edate of patientref table. Then we give highest values status is 2, and status 2 values have two records, then we go for max sdate(latest sdate). Then this pn=2 latest sdates is 2015-02-10 and we need to retrieve the corresponding edate and status values.
Based on this, the desired output is below:
pn | code | date | doctorcode | sdate |edate |status
1 | 10 |2015-02-19 | 100 |2015-02-19 |2015-03-24 | 2
1 | 10 |2015-02-19 | 101 |2015-02-19 |2015-03-24 | 2
1 | 10 |2015-02-19 | 102 |2015-02-19 |2015-03-24 | 2
2 | 10 |2015-02-12 | 101 |2015-02-10 |2015-02-19 | 2
2 | 10 |2015-02-13 | 102 |2015-02-10 |2015-02-19 | 2
2 | 10 |2015-02-14 | 103 |2015-02-10 |2015-02-19 | 2
3 | 10 |2015-02-15 | 103 |2015-02-10 |2015-02-17 | 4
3 | 10 |2015-02-18 | 104 |2015-02-11 |2015-02-18 | 3
3 | 10 |2015-02-26 | 105 |2015-02-26 |2015-03-18 | 1
I tried it like this:
select
a.pn, a.code, a.doctorcode, a.date,
b.sdate, b.edate, b.status
from
patient a
left join
(select
b.pn, b.code, b.sdate, b.edate,
row_number() over (partition by pn, org
order by case when status=2 then 1 when status=4 then 2 when status=3 then 3 when status=1 then 4 end desc,sdate desc) as rn
from patientref) b on a.pn = b.pn and a.code = b.code
and a.rn = 1
and a.date between b.sdate and b.edate
But it does not give the expected result. How can I write the query to achieve this task in SQL Server?
First off, to handle the status sorting you should really have a table in your system showing how they can be sorted. This would just be a table that has the status ID and a sort order column showing sorting priority. However, for your query you can just create a table variable to manage it.
declare #statuses table
([status] int,
sort_order int)
insert into #statuses ([status], sort_order) values (2,0);
insert into #statuses ([status], sort_order) values (4,1);
insert into #statuses ([status], sort_order) values (3,2);
insert into #statuses ([status], sort_order) values (1,3);
Then you can use CROSS APPLY to query your patient table and use the highest priority record from your patientref table:
select
p.pn,
p.code,
p.date,
p.doctorcode,
ca.sdate,
ca.edate,
ca.status
from patient p
cross apply
(select
top 1
pr.pn,
pr.code,
pr.sdate,
pr.edate,
pr.status
from patientref pr
inner join #statuses s on pr.status = s.status
where pr.pn = p.pn
and pr.code = p.code
and p.date between pr.sdate and pr.edate
order by s.sort_order, pr.sdate desc) as ca

Flatten SQL for 4 tables

In SQL Server 2012, I have four tables that look like:
Issues:
IssueID | IssueTitle
1 | Light Bulb Burnt Out
2 | Thermostat not working
LocationTypes:
TypeID | Type
1 | Building
2 | Floor
3 | Room
Locations:
LocaltionID | TypeID | Location | ParentLocation
0 | 1 | default | 0
1 | 1 | Sears Tower | 0
2 | 1 | IDS | 0
3 | 2 | Floor 1 | 1
4 | 2 | Floor 2 | 1
5 | 2 | Floor 3 | 1
6 | 2 | Floor 4 | 1
7 | 2 | Floor 5 | 1
8 | 2 | Floor 6 | 1
9 | 2 | Floor 7 | 1
10 | 2 | Floor 8 | 1
108 | 3 | Room 101 | 3
109 | 3 | Room 102 | 3
110 | 3 | Room 110 | 3
111 | 3 | Room 202 | 4
112 | 3 | Room 300 | 5
175 | 2 | 1st Floor | 2
185 | 2 | 2nd Floor | 2
186 | 3 | Suite 295 | 185
IssueLocations:
IssueID | LocationId
1 | 1
1 | 5
1 | 112
2 | 2
2 | 185
And what I want to do is combine the tables so that I end up with one row for each issuer, with field names as column headers and the field values, so I end up with:
Result:
IssueID | IssueTitle | Building | Floor | Room
--------------------------------------------------------------------------
1 | Light Bulb Burnt Out | Sears Tower | Floor 1 | Room 300
2 | Thermostat not working | IDS | 2nd Floor |
Notice the second issue doesn't have a room (no locations are required), location less issues are valid. Note other constraints might cause a required location but I don't think that is not relevant for this question.
You need to use Pivot to transpose your rows to columns.
SQL FIDDLE DEMO
SELECT *
FROM (SELECT il.IssueID,
l.Location,
i.IssueTitle,
lt.Type
FROM Locations l
JOIN LocationTypes lt
ON l.TypeID = lt.TypeID
JOIN IssueLocations il
ON il.LocationId = l.LocaltionID
JOIN issues i
ON i.IssueID = il.IssueID) a
PIVOT (Max(location)
FOR type IN([Building],
[Floor],
[Room]))piv

Resources