I have the following tables:
Stores:
StoreID | Name
1 | Store1
2 | Store2
3 | Store3
EmID | StoreID
1 | 1
2 | 1
3 | 1
1 | 2
3 | 2
Employee:
EmID | Employee | Important
1 | Cashier | 1
2 | Manager | 1
3 | Guard | 0
I need a query to return StoreID and EmID where Employee is important (Important = 1) and the store and employee are not connected. Basically, the result should be:
StoreID | EmId
--------+-------
2 | 2
3 | 1
3 | 2
I have tried joins, outer joins / apply-es, except, cte, temporary tables, but still haven't found the answer.
Can someone help me with the code, or at least point me in the right direction?
Any idea will be very much appreciated.
Thanks.
You use a cross join to get the set of all possible employee/store combinations, and a left join to then remove the combinations that exist in the join table1:
declare #Stores table (StoreID int, Name char(6))
insert into #Stores (StoreID,Name) values
(1,'Store1'),
(2,'Store2'),
(3,'Store3')
declare #Employees table (EmID int, Employee varchar(8), Important bit)
insert into #Employees (EmID,Employee,Important) values
(1,'Cashier',1),
(2,'Manager',1),
(3,'Guard' ,0)
declare #Staffing table (EmID int, StoreID int)
insert into #Staffing (EmID,StoreID) values
(1,1),
(2,1),
(3,1),
(1,2),
(3,2)
select
*
from
#Stores s
cross join
#Employees e
left join
#Staffing st
on
s.StoreID = st.StoreID and
e.EmID = st.EmID
where
e.Important = 1 and
st.EmID is null
Results:
StoreID Name EmID Employee Important EmID StoreID
----------- ------ ----------- -------- --------- ----------- -----------
3 Store3 1 Cashier 1 NULL NULL
2 Store2 2 Manager 1 NULL NULL
3 Store3 2 Manager 1 NULL NULL
1The one I've named Staffing and you didn't name in the question. Note also (for future questions) that my presentation of the sample data takes up approximately as much space as yours in the question, provides the data types, and is a runnable script.
Please use Cross join followed by Left join and filter on IMP and StoreID null.
create table #Stores
(storeID int, Name varchar(100))
create table #ES
(empid int,storeID int)
create table #E
(eid int,employee varchar(100), imp int)
insert into #stores values(
1,'Store1'),
(2,'Store2'),
(3,'Store3')
insert into #ES values(
1,1),(2,1),(3,1),(1,2),(3,2)
insert into #E values
(1,'Cashier',1),
(2,'Manager', 1),
(3,'Guard',0)
select * from #Stores
select * from #ES
select * from #E
select #stores.storeid,#E.eid from #Stores
cross join #E
LEFT join #ES
on #ES.storeid = #Stores.storeid
and #E.eid = #ES.empid
where #E.imp = 1
and #ES.storeID is null
Try this query.
I assumed the table name of the "Employee" is dbo.Employee and table name of "Stores" is dbo.Stores and the intermediate table is "dbo.EmpStore"
SELECT S.StoreID, E.EmID
FROM dbo.Stores S
CROSS JOIN dbo.Employees E
LEFT JOIN dbo.EmpStore ES ON ES.EmID = E.EmID AND ES.StoreID = S.StoreID
WHERE E.Important=1 AND ES.EmID IS NULL
Related
I have a Table Animals
Id | Name | Count | -- (other columns not relevant)
1 | horse | 11
2 | giraffe | 20
I want to try to insert or update values from a CSV string
Is it possible to do something like the following in 1 query?
;with results as
(
select * from
(
values ('horse'), ('giraffe'), ('lion')
)
animal_csv(aName)
left join animals on
animals.[Name] = animal_csv.aName
)
update results
set
[Count] = 1 + animals.[Count]
-- various other columns are set here
where Id is not null
--else
--insert into results ([Name], [Count]) values (results.aName, 1)
-- (essentially Where id is null)
It looks like what you're looking for is a table variable or temporary table rather than a common table expression.
If I understand your problem correctly, you are building a result set based on data you're getting from a CSV, merging it by incrementing values, and then returning that result set.
As I read your code, it looks as if your results would look like this:
aName | Id | Name | Count
horse | 1 | horse | 12
giraffe | 2 | giraffe | 21
lion | | |
I think what you're looking for in your final result set is this:
Name | Count
horse | 12
giraffe | 21
lion | 1
First, you can get from your csv and table to a resultset in a single CTE statement:
;WITH animal_csv AS (SELECT * FROM (VALUES('horse'),('giraffe'), ('lion')) a(aName))
SELECT ISNULL(Name, aName) Name
, CASE WHEN [Count] IS NULL THEN 1 ELSE 1 + [Count] END [Count]
FROM animal_csv
LEFT JOIN animals
ON Name = animal_csv.aName
Or, if you want to build your resultset using a table variable:
DECLARE #Results TABLE
(
Name VARCHAR(30)
, Count INT
)
;WITH animal_csv AS (SELECT * FROM (VALUES('horse'),('giraffe'), ('lion')) a(aName))
INSERT #Results
SELECT ISNULL(Name, aName) Name
, CASE WHEN [Count] IS NULL THEN 1 ELSE 1 + [Count] END [Count]
FROM animal_csv
LEFT JOIN animals
ON Name = animal_csv.aName
SELECT * FROM #results
Or, if you just want to use a temporary table, you can build it like this (temp tables are deleted when the connection is released/closed or when they're explicitly dropped):
;WITH animal_csv AS (SELECT * FROM (VALUES('horse'),('giraffe'), ('lion')) a(aName))
SELECT ISNULL(Name, aName) Name
, CASE WHEN [Count] IS NULL THEN 1 ELSE 1 + [Count] END [Count]
INTO #results
FROM animal_csv
LEFT JOIN animals
ON Name = animal_csv.aName
SELECT * FROM #results
Table1
Columns PK_Table1 Name | DoYouGoToSchool |DoYouhaveACar |DoYouWorkFullTime | DoYouWorkPartTime | Score
1 joe Yes Yes No Yes
2 amy No Yes Yes No
Table2
Columns Pk_Table2 |Question | Answer(Bit Column) |Value
1 DoYouGoToSchool True 3
2 DoYouhaveACar True 2
3 DoYouWorkFullTime True 4
4 DoYouWorkPartTime True 2
Based on the information from Table2 What i need to do is UPDATE Table1 ColumnName Score by summing up the Value from Table2 with the information he has provided.
for example i expect the Score column in table1 to be 7 for record 1
and 5 for record 2
Here is a query to play with
IF OBJECT_ID('tempdb..#Table2') IS NOT NULL DROP TABLE #Table2
GO
IF OBJECT_ID('tempdb..#Table1') IS NOT NULL DROP TABLE #Table1
GO
create table #Table1
(
PK_Table1 int,
Name Varchar(50),
DoYouGoToSchool Varchar(8),
DoYouhaveACar Varchar(8),
DoYouWorkFullTime Varchar(8),
DoYouWorkPartTime Varchar(8),
Score INT NULL,
)
create table #Table2
(
PK_Table2 int,
Questions Varchar(50),
Answer BIT NOT NULL DEFAULT(0),
VALUE INT NULL
)
INSERT INTO #Table1 (Name,DoYouGoToSchool,DoYouhaveACar,DoYouWorkFullTime,DoYouWorkPartTime)
VALUES ('joe','Yes','Yes','No','Yes'), ('amy','NO','Yes','Yes','No')
INSERT INTO #Table2(Questions,Answer,VALUE)
VALUES ('DoYouGoToSchool','True',3 ),('DoYouhaveACar','True',2 ),('DoYouWorkFullTime','True',4 ),('DoYouWorkPartTime','True',2 )
This is what is missing from answer below that tells you to create new FK contraint to the Table2 --Inserting Data into the table with the new FK Column
insert into #Table2 (FK_Table1, Questions, Answer) select t.PK_Table1, t1.cols, colsval from #Table1 t cross apply (values (PK_Table1,'DoYouGoToSchool', DoYouGoToSchool), (PK_Table1,'DoYouhaveACar', DoYouhaveACar), (PK_Table1,'DoYouWorkFullTime', DoYouWorkFullTime), (PK_Table1,'DoYouWorkPartTime', DoYouWorkPartTime) ) t1 (PK_Table1,cols, colsval);
First create a relation between these two tables and add Primary key of Table1 in Table2 as a foreign key so your Table2 becomes:
Table2 Columns:
FK_Table1 |Pk_Table2 |Question | Answer(Bit Column) |Value
1 1 DoYouGoToSchool True 3
1 2 DoYouhaveACar True 2
1 3 DoYouWorkFullTime True 4
1 4 DoYouWorkPartTime True 2
You can add in table by using this Query:
ALTER TABLE Table2
ADD FK_Table1 INTEGER,
ADD CONSTRAINT FOREIGN KEY(FK_Table1) REFERENCES Table1(PK_Table1)
means that it is only for that person whose PK_Table1 = 1
Then you can extract his score from this query:
SELECT Sum(Value) FROM Table2 WHERE FK_Table1 = 1;
And then update query:
UPDATE Table1
SET score = (enter here the returned score from above query)
WHERE PK_Table1 = 1;
Or you can do in a single query like this:
UPDATE Table1
SET score = (SELECT Sum(Value) FROM Table2 WHERE FK_Table1 = 1)
WHERE PK_Table1 = 1;
You will need to add another table. This table will be your relational table. It can be called Table1_Table2 with three columns. The first column will be the primary key for the table. The next column will be the primary key of Table1 and the third column will be the primary key for Table 2.
When an instance of Table2 occurs that relates with Table1, insert a record into Table1_Table2 that relates the two tables together with each others primary key. Then a query can be done on the relational table, Table1_Table2 that allows you to sum the relationships.
|Table1_Table2 |
| PK | PK_Table1 | PK_Table2 |
| 1 | 1 | 1 |
| 2 | 1 | 3 |
| 3 | 2 | 1 |
| 4 | 2 | 4 |
As we can see, we can now perform an update on Table1
UPDATE TABLE1 A SET A.SCORE = (Select SUM(B.Value) FROM Table2 B, Table1_Table2 C WHERE C.PK_Table2 = B.PK_Table2 AND C.PK_Table1 = A.PK_Table1);
I have 2 tables:
Product:
ProductId | Name | Description
----------+-------+-------------------------------------
1 | shirt | this is description for shirt
2 | pent | this is description for pent
ProductOverride:
ProductOverrideId | ColumnId | Value | ProductId
------------------+-----------+------------------------+-----------
1 | 1 | overridden name | 1
2 | 2 | overridden description | 1
where ColumnId is column_id from sys.columns.
I want to select all the products with the following requirement:
if product name or product description is overridden in ProductOverride table, get the overridden value of name/description, otherwise get the name/description value from the product table.
Sample output:
ProductId | Name | Description
----------+-----------------+---------------------------
1 | overridden name | overridden description
2 | pent | this is description for pent
I have the following query which returns the exact result.
DECLARE #productNameColumnId INT = 1;
DECLARE #productDescriptionColumnId INT = 2;
WITH OverriddenProductNameCTE ([Value], [ProductId]) AS
(
SELECT
temp.[Value], temp.ProductId
FROM
ProductOverride temp
WHERE
temp.ColumnId = #productNameColumnId
), OverriddenProductDescriptionCTE ([Value], [ProductId]) AS
(
SELECT
temp.[Value], temp.ProductId
FROM
ProductOverride temp
WHERE
temp.ColumnId = #productDescriptionColumnId
)
SELECT
p.ProductId,
CASE
WHEN EXISTS(SELECT [Value]
FROM OverriddenProductNameCTE opnc
WHERE opnc.ProductId = p.ProductId)
THEN (SELECT [Value]
FROM OverriddenProductNameCTE opnc
WHERE opnc.ProductId = p.ProductId)
ELSE p.[Name]
END AS [Name],
CASE
WHEN EXISTS(SELECT [Value]
FROM OverriddenProductDescriptionCTE opdc
WHERE opdc.ProductId = p.ProductId)
THEN (SELECT [Value]
FROM OverriddenProductDescriptionCTE opdc
WHERE opdc.ProductId = p.ProductId)
ELSE p.[Description]
END AS [Description]
FROM
product p
but in the CASE statements, I have the following repetitive code:
SELECT [Value]
FROM OverriddenProductNameCTE opnc
WHERE opnc.ProductId = p.ProductId
which means if the CASE statement's first condition is true DBMS will execute the same query again in the THEN part.
I want to improve this query both in terms of simplifying the query and in terms of processing.
Also if there is any advantage of using CTEs in this situation?
If it's only 2 columns I think the simplest thing you can do is left join twice with coalesce:
SELECT p.ProductId
,COALESCE(poN.Value, p.Name) As Name
,COALESCE(poD.Value, p.Description) As Description
FROM Product p
LEFT JOIN ProductOverride poN ON p.ProductId = poN.ProductId AND poN.ColumnId = 1
LEFT JOIN ProductOverride poD ON p.ProductId = poD.ProductId AND poD.ColumnId = 2
If it's more columns I would suggest pivoting the ProductOverride table and left join to that - Like this (a complete example):
Create and populate sample tables (Please save us this step in your future questions)
CREATE TABLE Product
(
ProductId int,
Name varchar(100),
Description varchar(100),
price int null
);
INSERT INTO Product VALUES
(1, 'shirt', 'Description for shirts', 1),
(2, 'Pants', 'Description for pants', 4),
(3, 'Socks', 'Description for socks', 5)
CREATE TABLE ProductOverride
(
ProductOverrideId int,
ColumnId int,
Value varchar(100),
ProductId int
);
INSERT INTO ProductOverride VALUES
(1,1,'product 1 name',1),
(2,2,'product 1 desc',1),
(3,3,'7',1),
(4,1,'pants name',2),
--Note: no pants description in the override tabl
(6,3,'8',2);
-- Note: no socks at all in override table
The query:
SELECT p.ProductId
,COALESCE(override.[1], p.Name) As Name
,COALESCE(override.[2], p.Description) As Description
,COALESCE(CAST(override.[3] as int), p.Price) As Price
FROM Product p
LEFT JOIN
(
SELECT *
FROM
(
SELECT ProductId, Value, ColumnId -- Columns To use for pivot
FROM ProductOverride
) ColumnsToPivot
PIVOT (
max (Value)
for ColumnId in ([1], [2], [3]) -- Values in ColumnId column to make the column names
) as pivotedData
) as override ON p.ProductId = override.ProductId
Results:
ProductId Name Description Price
1 product 1 name product 1 desc 7
2 pants name Description for pants 8
3 Socks Description for socks 5
You can see a live demo on rextester.
I need to copy some master-detail records, along the lines of:
INSERT INTO Order
(
SupplierId
,DateOrdered
)
SELECT
SupplierID
,DateOrdered
FROM Order
WHERE SupplierId = 10
DECLARE #OrderId int;
Select #OrderId = Scope_Identity;
INSERT INTO OrderItem
(
Quantity
,ProductCode
,Price
,FkOrderId
)
SELECT
Quantity
,ProductCode
,Price
,FkOrderId
FROM OrderItem
WHERE FkOrderId = #OrderId
This will not work. The reason is that there are multiple Orders for Supplier = 10. So what is the best way to iterate through each Order where Supplier = 10, Add the order, and then add the relevant child OrderItem BEFORE going onto the next Order Record where supplier=10. I think I am talking about batching, possibly cursors, but I am a newbie to T-SQL / Store Procedures.
I would appreciate advice on the above.
Thanks.
EDIT
Some more information which I hope will clarify by virtue of some sample data.
Original Order Table
Id SupplierId DateOrdered
1 10 01/01/2000
2 10 01/01/2000
Original OrderItem Table
Id Quantity ProductCode Price FkOrderId
1 20 X1 100 1
2 10 Y1 50 1
3 30 X1 100 2
4 20 Y1 50 2
Final Order Table
Id SupplierId DateOrdered
1 10 01/01/2000
2 10 01/01/2000
3 10 01/01/2000 (Clone of 1)
4 10 01/01/2000 (Clone of 2)
Final OrderItem Table
Id Quantity ProductCode Price FkOrderId
1 20 X1 100 1
2 10 Y1 50 1
3 30 X1 100 2
4 20 Y1 50 2
5 20 X1 100 3 (Clone of 1, linked to clone Order=3)
6 10 Y1 50 3 (Clone of 2, linked to clone Order=3)
7 30 X1 100 4 (Clone of 3, linked to clone Order=4)
8 20 Y1 50 5 (Clone of 4, linked to clone Order=4)
So I need some help with the code can do this cloning of Order and OrderItem to achieve the "final" table records.
It seems I need to do something like:
For each matching record in "Order"
Clone Order Record
Clone OrderItem Record where FkOrderId = OldOrderId
Next
This answers your question (no cursors either)
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE [Order]
(
Id Int Primary Key Identity,
SupplierId Int,
DateOrdered Date
)
SET IDENTITY_INSERT [Order] ON
INSERT INTO [Order] (Id, SupplierId, DateOrdered)
VALUES
(1, 10, '01/01/2000'),
(2, 10, '01/01/2000')
SET IDENTITY_INSERT [Order] OFF
CREATE TABLE [OrderItem]
(
ID INT Primary Key Identity,
Quantity Int,
ProductCode CHAR(2),
Price Int,
FKOrderId Int
)
SET IDENTITY_INSERT [OrderItem] ON
INSERT INTO [OrderItem] (Id, Quantity, ProductCode, Price, FKOrderId)
VALUES
(1, 20, 'X1', 100, 1),
(2, 10, 'Y1', 50, 1),
(3, 30, 'X1', 100, 2),
(4, 20, 'Y1', 50, 2)
SET IDENTITY_INSERT [OrderItem] OFF
Query 1:
DECLARE #NewEntries TABLE (ID Int, OldId Int);
MERGE INTO [Order]
USING [Order] AS cf
ON 1 = 0 -- Ensure never match - therefore an Insert
WHEN NOT MATCHED AND cf.SupplierId = 10 THEN
INSERT(SupplierId, DateOrdered) Values(cf.SupplierId, cf.DateOrdered)
Output inserted.Id, cf.Id INTO
#NewEntries(Id, OldId);
INSERT INTO [OrderItem]
(
Quantity
,ProductCode
,Price
,FkOrderId
)
SELECT
Quantity
,ProductCode
,Price
,NE.ID
FROM [OrderItem] OI
INNER JOIN #NewEntries NE
ON OI.FKOrderId = NE.OldId ;
SELECT *
FROM [OrderItem];
Results:
| ID | QUANTITY | PRODUCTCODE | PRICE | FKORDERID |
|----|----------|-------------|-------|-----------|
| 1 | 20 | X1 | 100 | 1 |
| 2 | 10 | Y1 | 50 | 1 |
| 3 | 30 | X1 | 100 | 2 |
| 4 | 20 | Y1 | 50 | 2 |
| 5 | 20 | X1 | 100 | 3 |
| 6 | 10 | Y1 | 50 | 3 |
| 7 | 30 | X1 | 100 | 4 |
| 8 | 20 | Y1 | 50 | 4 |
Add an additional column to the Order table called OriginalOrderId. Make it nullable, FK'd back to OrderId, and put an index on it. Use "INSERT INTO [Order]... SELECT ... OUTPUT INSERTED.* INTO #ClonedOrders From ...". Add an index on #ClonedOrders.OriginalOrderId. Then you can do "INSERT INTO OrderItem ... SELECT co.OrderId, ... FROM #ClonedOrders co INNER JOIN OrderItem oi ON oi.OrderId = co.OriginalOrderId". This will get you the functionality that you're looking for, along with the performance benefits of set based statements. It will also leave you evidence of the original source of the orders and a field that you can use to differentiate cloned orders from non-cloned orders.
in this case you have to use output clause.. let me give you one sample script that will help you to relate with your requirement
Declare #Order AS Table(id int identity(1,1),SupplierID INT)
DECLARE #outputOrder AS TABLE
(Orderid INT)
INSERT INTO #Order (SupplierID)
Output inserted.id into #outputOrder
Values (102),(202),(303)
select * from #outputOrder
next step for your case would be use newly generated orderid from outputorder table & join to get orderitems from input table
This will handle your first table.
PS: Supply your questions in this state and they will be answered faster.
IF OBJECT_ID('Orders') IS NOT NULL DROP TABLE Orders
IF OBJECT_ID('OrderItem') IS NOT NULL DROP TABLE OrderItem
IF OBJECT_ID('tempdb..#FinalOrders') IS NOT NULL DROP TABLE #FinalOrders
CREATE TABLE Orders (OrdersID INT, SupplierID INT, DateOrdered DATETIME)
CREATE TABLE OrderItem (OrderItemID INT, Quantity INT, FkOrderId INT)
INSERT INTO Orders VALUES (1,20,'01/01/2000'),(2,20,'01/01/2000')
INSERT INTO OrderItem VALUES
(1,20,1),
(2,10,1),
(3,30,2),
(4,20,2)
SELECT
a.OrderItemID,
b.SupplierID,
b.DateOrdered
INTO #FinalOrders
FROM OrderItem as a
INNER JOIN Orders as b
ON a.FkOrderId = b.OrdersID
SELECT * FROM #FinalOrders
This can be achieved with a cursor. But please note that cursors will pose significant performance drawbacks.
DECLARE #SupplierID AS INT
DECLARE #OrderId AS INT
DECLARE #DateOrdered AS DATE
DECLARE #OrderIdNew AS INT
Declare #Order AS Table(OrderId INT,SupplierID INT,DateOrdered Date)
INSERT INTO #Order
SELECT
ID
,SupplierID
,DateOrdered
FROM [Order]
WHERE SupplierId = 10
DECLARE CUR CURSOR FAST_FORWARD FOR
SELECT
OrderId
,SupplierID
,DateOrdered
FROM #Order
OPEN CUR
FETCH NEXT FROM CUR INTO #OrderId, #SupplierID, #DateOrdered
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO [Order]
(
SupplierId
,DateOrdered
)
VALUES
(#SupplierID,#DateOrdered)
Select #OrderIdNew=##IDENTITY
INSERT INTO [OrderItem]
([Quantity]
,[ProductCode]
,[Price]
,[FkOrderId])
SELECT [Quantity]
,[ProductCode]
,[Price]
,#OrderIdNew
FROM [OrderItem]
WHERE [FkOrderId]=#OrderId
FETCH NEXT FROM CUR INTO #OrderId, #SupplierID, #DateOrdered
END
CLOSE CUR;
DEALLOCATE CUR;
You could try doing and inner join between Order and OrderItems where the clause of the inner join is SupplierId = 10,
or just modify your where to achieve the same result.
Try doing something along the lines of:
INSERT INTO OrderItem
(
Quantity
,ProductCode
,Price
,FkOrderId
)
SELECT
Quantity
,ProductCode
,Price
,FkOrderId
FROM OrderItem
where FkOrderId in (Select Id FROM Order WHERE SupplierId = 10)
I've searched high and low for an answer to this so apologies if it's already answered!
I have the following result from a query in SQL 2005:
ID
1234
1235
1236
1267
1278
What I want is
column1|column2|column3|column4|column5
---------------------------------------
1234 |1235 |1236 |1267 |1278
I can't quite get my head around the pivot operator but this looks like it's going to be involved. I can work with there being only 5 rows for now but a bonus would be for it to be dynamic, i.e. can scale to x rows.
EDIT:
What I'm ultimately after is assigning the values of each resulting column to variables, e.g.
DECLARE #id1 int, #id2 int, #id3 int, #id4 int, #id5 int
SELECT #id1 = column1, #id2 = column2, #id3 = column3, #id4 = column4,
#id5 = column5 FROM [transposed_table]
You also need a value field in your query for each id to aggregate on. Then you can do something like this
select [1234], [1235]
from
(
-- replace code below with your query, e.g. select id, value from table
select
id = 1234,
value = 1
union
select
id = 1235,
value = 2
) a
pivot
(
avg(value) for id in ([1234], [1235])
) as pvt
I think you'll find the answer in this answer to a slightly different question: Generate "scatter plot" result of members against sets from SQL query
The answer uses Dynamic SQL. Check out the last link in mellamokb's answer: http://www.sqlfiddle.com/#!3/c136d/14 where he creates column names from row data.
In case you have a grouped flat data structure that you want to group transpose, like such:
GRP | ID
---------------
1 | 1234
1 | 1235
1 | 1236
1 | 1267
1 | 1278
2 | 1234
2 | 1235
2 | 1267
2 | 1289
And you want its group transposition to appear like:
GRP | Column 1 | Column 2 | Column 3 | Column 4 | Column 5
-------------------------------------------------------------
1 | 1234 | 1235 | 1236 | 1267 | 1278
2 | 1234 | 1235 | NULL | 1267 | NULL
You can accomplish it with a query like this:
SELECT
Column1.ID As column1,
Column2.ID AS column2,
Column3.ID AS column3,
Column4.ID AS column4,
Column5.ID AS column5
FROM
(SELECT GRP, ID FROM FlatTable WHERE ID = 1234) AS Column1
LEFT OUTER JOIN
(SELECT GRP, ID FROM FlatTable WHERE ID = 1235) AS Column2
ON Column1.GRP = Column2.GRP
LEFT OUTER JOIN
(SELECT GRP, ID FROM FlatTable WHERE ID = 1236) AS Column3
ON Column1.GRP = Column3.GRP
LEFT OUTER JOIN
(SELECT GRP, ID FROM FlatTable WHERE ID = 1267) AS Column4
ON Column1.GRP = Column4.GRP
LEFT OUTER JOIN
(SELECT GRP, ID FROM FlatTable WHERE ID = 1278) AS Column5
ON Column1.GRP = Column5.GRP
(1) This assumes you know ahead of time which columns you will want — notice that I intentionally left out ID = 1289 from this example
(2) This basically uses a bunch of left outer joins to append 1 column at a time, thus creating the transposition. The left outer joins (rather than inner joins) allow for some columns to be null if they don't have corresponding values from the flat table, without affecting any subsequent columns.