Using Multiple CTE with one INSERT statement. [Error:More Columns than Specified in Column List] - sql

I have CTE1 and CTE2 as below. The CTE2 shows error
CTE2 has more columns than specified in the column list
I would like to know what I am doing wrong. It cannot be because Insert statement has more columns than the CTE2 because CTE1 worked fine before. CTE1 and CTE2 are both using different tables. Is that the problem?
If I remove the parameters in CTE2(NewRoomCost,NewQuantity) Then I get the error
No Columns specified for Column3 of CTE2
Below is the code that I tried. Any help would be appreciated.
CREATE PROCEDURE dbo.SpTransactionGenerate
AS
BEGIN
SET NOCOUNT ON
DECLARE #MinReservationId INT = (SELECT MIN(f.ReservationId) FROM dbo.Reservation AS f)
DECLARE #MaxReservationId INT = (SELECT MAX(f.ReservationId) FROM dbo.Reservation AS f)
DECLARE #FirstSeasonEndDate DATE= '2018-02-13';
DECLARE #SecondSeasonEndDate DATE='2018-02-14';
DECLARE #ThirdSeasonEndDate DATE='2018-12-31';
WHILE #MinReservationId<=#MaxReservationId
BEGIN
WITH CTE1(ServiceId,ServiceRate,Quantity) AS
(
SELECT ServiceId,
ServiceRate,
ABS(CHECKSUM(NEWID())%3) + 1 AS Quantity
FROM dbo.[Service]
),
CTE2(NewRoomCost,NewQuantity) AS
(
SELECT
(SELECT roomRate.RoomCost FROM dbo.RoomRate as roomRate WHERE roomRate.RoomTypeId=
(SELECT room.RoomTypeId FROM dbo.Room as room
JOIN dbo.Reservation as res ON res.RoomId=room.RoomId WHERE res.ReservationId=#MinReservationId
AND roomRate.SeasonId=(
CASE WHEN (SELECT resv.CheckInDate FROM dbo.Reservation as resv WHERE resv.ReservationId=#MinReservationId)<=#FirstSeasonEndDate
THEN (SELECT sea.SeasonId FROM dbo.Season as sea WHERE sea.SeasonEndDate=#FirstSeasonEndDate)
WHEN (SELECT resv.CheckInDate FROM dbo.Reservation as resv WHERE resv.ReservationId=#MinReservationId)<=#SecondSeasonEndDate
THEN (SELECT sea.SeasonId FROM dbo.Season as sea WHERE sea.SeasonEndDate=#SecondSeasonEndDate)
ELSE (SELECT sea.SeasonId FROM dbo.Season as sea WHERE sea.SeasonEndDate=#ThirdSeasonEndDate) END
)
)) AS NewRoomCost,
DATEDIFF(DAY,(SELECT r.CheckinDate FROM dbo.Reservation AS r WHERE r.ReservationId=#MinReservationId), (SELECT r.CheckOutDate FROM dbo.Reservation AS r WHERE r.ReservationId=#MinReservationId)) AS NewQuantity,
)
INSERT INTO dbo.[Transaction]
(
ReservationId,
ServiceId,
Rate,
Quantity,
Amount
)
SELECT
#MinReservationId,
ServiceId,
ServiceRate,
Quantity,
ServiceRate*Quantity
FROM CTE1
UNION
SELECT
#MinReservationId,
NULL,
NewRoomCost,
NewQuantity,
NewRoomCost*NewQuantity
FROM CTE2
SELECT #MinReservationId=#MinReservationId+1
END
END
UPDATE : The error resulted because of a single extra comma in the CTE2. Sorry for the unnecessary question asked.

The issue in CTE2 is that you have an extra comma at the end of this line:
DATEDIFF(DAY,(SELECT r.CheckinDate FROM dbo.Reservation AS r WHERE r.ReservationId=#MinReservationId), (SELECT r.CheckOutDate FROM dbo.Reservation AS r WHERE r.ReservationId=#MinReservationId)) AS NewQuantity,
A sidenote: I suggest not writing explicit column names in the future but rather just naming them as you already did with the AS keyword. It just gives more flexibility overall.

Because your 2nd CTE defines two columns:
CTE2(NewRoomCost,NewQuantity) AS
But your select statement returns 3.
(SELECT roomRate.RoomCost FROM...
DATEDIFF(DAY,(SELECT r.CheckinDate...
(SELECT r.CheckOutDate FROM dbo.Reservation...

Related

Cross apply boolean values in SQL

I had the table below which I need to create a Category column will store the boolean values as a category.
I would like to capture the Categories as a single column and I don't mind having duplicate rows in the view. I would like the first row to return Contract and the second the other value selected, for the same Reference ID.
I achieved his using the query below:
select distinct t.*, tt.category
from t cross apply
( values ('Contracts', t.Contracts),
('Tender', t.Tender),
('Waiver', t.Waiver),
('Quotation', t.Quotation)
) tt(category, flag)
where flag = 1;
How can I capture an additional Category None where all instances of Contract, Tender, Waiver and Quotation are 0?
None can go right into your VALUES clause. You case use a case expression for the logic. Alternatively, you can use a trick with sign():
select distinct t.*, tt.category
from t cross apply
( values ('Contracts', t.Contracts),
('Tender', t.Tender),
('Waiver', t.Waiver),
('Quotation', t.Quotation),
('None', 1 - sign(t.Contracts + t.Tender + t.Waiver + t.Quotation))
) tt(category, flag)
where flag = 1;
I am guessing that you don't have duplicates in your original table, so you should dispense with SELECT DISTINCT.
Maybe something like this:
select distinct t.*, tt.category
from t cross apply
( values ('Contracts', t.Contracts),
('Tender', t.Tender),
('Waiver', t.Waiver),
('Quotation', t.Quotation),
('None', -1)
) tt(category, flag)
where flag = 1 or
(Contracts = 0 and Tender = 0 and Waiver = 0 and Quotation = 0 and flag = -1);
Here's my sample fiddle (guessing you have bit fields, but it works with int fields too): http://sqlfiddle.com/#!18/9f8e7/1
I hope following SQL query can also help you
create table myTable (
ReferenceId int,
Contract int,
Tender int,
Waiver int,
Quotation int
)
insert into myTable select 1212,1,0,1,0
insert into myTable select 1213,1,1,0,0
insert into myTable select 1214,0,1,0,0
insert into myTable select 1215,1,0,1,0
insert into myTable select 1216,0,0,0,1
insert into myTable select 1217,0,0,1,0
insert into myTable select 1218,0,0,0,0
;with cte as (
select
*,
ISNULL(NULLIF(
CONCAT_WS(',',
case when Contract = 1 then 'Contract' end,
case when Tender = 1 then 'Tender' end,
case when Waiver = 1 then 'Waiver' end,
case when Quotation = 1 then 'Quotation' end
)
,''),'None')
as Category
from myTable
)
select
ReferenceId, Contract, Tender, Waiver, Quotation, c.val as Category
from cte
cross apply split(Category,',') as c
Here you need a user-defined SQL function SPLIT where the source codes can be found
The output as follows
declare #t table
(
ReferenceId int,
Contracts bit,
Tender bit,
Waiver bit,
Quotation bit
)
insert into #t(ReferenceId, Contracts, Tender, Waiver, Quotation)
values
(123, 0, 1, 0, 0),
(234, 0, 0, 0, 1),
(345, 0, 0, 0, 0);
select *
from
(
select ReferenceId,
Contracts, nullif(Tender, 0) as Tender, nullif(Waiver, 0) as Waiver, nullif(Quotation, 0) as Quotation,
case when cast(Contracts as int)+Tender+Waiver+Quotation > 0 then cast(null as bit) else cast(0 as bit) end as [None]
from #t
)as t
unpivot
(
Flag for Category in (Contracts, Tender, Waiver, Quotation, [None])
) as unpv;
This is ugly, but I don't think it's a bad idea
select *, 'contract' as category
from t where contract=1 union
select *, 'waiver'
from t where waiver=1 union
select *, 'tender'
from t where tender=1 union
select *, 'quotation'
from t where quotation=1 union
select *, 'none'
from t where (contract+waiver+tender+quotation)=0
order by referenceid;

query on sql server

I have the following query
SELECT
A.IdDepartment,
A.IdParent,
A.Localidad,
A.Codigo,
A.Nombre,
A.Departamento,
A.Fecha,
A.[Registro Entrada],
A.[Registro Salida],
CASE
WHEN (SELECT IdUser FROM Exception WHERE IdUser = A.Codigo) <> ''
THEN(SELECT Description FROM Exception WHERE IdUser = A.Codigo AND A.Fecha BETWEEN BeginingDate AND EndingDate)
ELSE ('Ausente')
END AS Novedades
FROM VW_HORARIOS A
WHERE A.[Registro Entrada] = A.[Registro Salida]
GROUP BY A.IdDepartment,A.IdParent, A.Localidad, A.Codigo, A.Nombre, A.Departamento, A.Fecha, A.[Registro Entrada],A.[Registro Salida]
ORDER BY A.Fecha
the query performs the following selects all the records placed in the following query, what I want to validate is the following if on a date there was no record I want to create it but I do not know how to create that record because it does not exist, if someone can help me I would appreciate the help
You can try something like this. Just fill out your own Date table with values that is within your range of dates.
Remember to verify the last join. I dont know if that is the unique businesskey within your data sample
SQL Test Code
declare #DateTable table (Dates date)
insert into #DateTable
values
('2017-01-01'),
('2017-01-02'),
('2017-01-03'),
('2017-01-04'),
('2017-01-05'),
('2017-01-06'),
('2017-01-07'),
('2017-01-08'),
('2017-01-09'),
('2017-01-10')
declare #SamleTable table (DateStamp date,Department nvarchar(50),LocationId nvarchar(50),Code int,name nvarchar(50),Entrada nvarchar(50))
insert into #SamleTable
values
('2017-01-01','BOTELLO','SANTO',5540,'JOSE','Something'),
('2017-01-04','BOTELLO','SANTO',5540,'JOSE','Something'),
('2017-01-06','BOTELLO','SANTO',5540,'JOSE','Something'),
('2017-01-09','BOTELLO','SANTO',5540,'JOSE','Something')
select z.Department,z.LocationId,z.Code,z.name,z.Dates,COALESCE(a.Entrada,'EMPTY') as Entrada from (
Select Department,LocationId,Code,Name,Dates from (
select Department,LocationId,Code,Name,MIN(DateStamp) mind, MAX(Datestamp) maxd from #SamleTable
group by Department,LocationId,Code,Name
)x
CROSS JOIN #DateTable b
where b.Dates between x.mind and x.maxd
) z
left join #SamleTable a on a.Department = z.Department and a.LocationId = z.LocationId and a.Code = z.Code and a.name = z.name
and a.DateStamp = z.Dates
Result
You can use a recursive query building all dates from the minimum date to the maximum date found in your table.
with dates(fecha, maxfecha) as
(
select min(fecha) as fecha, max(fecha) as maxfecha from vw_horarios
union all
select dateadd(dd, 1, fecha) as fecha, maxfecha from dates where fecha < maxfecha
)
select d.fecha, q.*
from dates d
left join ( your query here ) q on q.fecha = d.fecha;

UFT retrieve data from SQL: Item cannot be found in the collection

Using UFT12.51. Need to retrieve data from SQL Server.
Same question was asked by many people, but researching several posts, could not find any answer.
The query to run is:
DROP TABLE IF EXISTS dbo.TempTableOutgoing, TempTableOutgoingLeft, TempTableOutgoingRight;
SELECT Table1.RowNum, Table1.present, Table2.Amount INTO TempTableOutgoingLeft FROM
(Select cte.* FROM (VALUES ('1','1st Present'), ('2','1P 1-Sided'), ('3','')
) as cte (RowNum,present)) AS Table1
LEFT OUTER JOIN (SELECT ca.* FROM [eBalance].[dbo].[TRANS_DISTRIB] AS t1
CROSS APPLY (Values
('1', CONVERT(VARCHAR, FirstPresent)),
('2', CONVERT(VARCHAR, FirstPresentOneSided)),
('3',NULL)
) AS ca (RowNum, Amount)
WHERE t1.FileDate = ''"&FileDate&"'' AND t1.CardType = 'AMEX') as Table2
on Table1.RowNum = Table2.RowNum;
SELECT * INTO TempTableOutgoingRight FROM(
SELECT vi.rownumber, vi.outgoing, vi.oamount FROM [eBalance].[dbo].[AMEX_OUTGOING] AS V1
CROSS APPLY (Values ('1','Sales', Sales),
('2','Cash Advances', CashAdvances),
('3','Returns', Credits)
) as vi (rownumber, outgoing, oamount)
WHERE v1.FileDate = ''"&FileDate&"'')R;
SELECT RowNum, Present, Amount, Outgoing, OAmount INTO TempTableOutgoing FROM(
SELECT * FROM(SELECT * FROM TempTableOutgoingLeft
UNION ALL
SELECT '4','Total', CONVERT(VARCHAR, SUM(CAST(ISNULL(Amount,'0') AS decimal(15,2)))) from TempTableOutgoingLeft) AS Table1
LEFT OUTER JOIN (SELECT * FROM TempTableOutgoingRight
UNION ALL
SELECT '4','Outgoing Settlement Total', CONVERT(VARCHAR, SUM(CAST(ISNULL(oamount,'0') AS decimal(15,2)))) from TempTableOutgoingRight) AS Table2
ON Table1.RowNum = Table2.rownumber) Z;
DROP TABLE TempTableOutgoingLeft;
DROP TABLE TempTableOutgoingRight;
SELECT present, Amount, Outgoing, OAmount, Variance FROM(
SELECT * FROM dbo.TempTableOutgoing z1
INNER JOIN (Select RowN, Variance from (
SELECT DISTINCT RowN, Variance FROM TempTableOutgoing AS TTO
CROSS APPLY (Values
('1',''),('2', (SELECT CONVERT(VARCHAR, SUM(CAST(ISNULL(Amount,'0') AS decimal(15,2)))-SUM(CAST(ISNULL(OAmount,'0') AS decimal(15,2))))
FROM TempTableOutgoing where RowNum IN (1,2,3))), ('3',''))
as z (RowN,Variance) where TTO.RowNum IN (1,2,3)
UNION ALL
SELECT DISTINCT z.* FROM TempTableOutgoing AS TTO
CROSS APPLY (Values
('4', (SELECT CONVERT(VARCHAR, SUM(CAST(ISNULL(Amount,'0') AS decimal(15,2)))-SUM(CAST(ISNULL(OAmount,'0') AS decimal(15,2))))
FROM TempTableOutgoing where RowNum IN (4)))
) as z (RowN,Variance) where TTO.RowNum IN (4)
) V Group by RowN, Variance) V1
on z1.RowNum = V1.RowN) T;
When running in SQL Management Studio, it works well and gives proper result:
present |Amount |Outgoing |OAmount |Variance
============+===========+=========================+===========+========
1st Present |5028510.18 |Sales |5110968.89
------------+-----------+-------------------------+-----------+--------
1P 1-Sided |0.00 |Cash Advances |0.00 |0.00
------------+-----------+-------------------------+-----------+--------
|NULL |Returns |-82458.71 |
------------+-----------+-------------------------+-----------+--------
Total |5028510.18 |Outgoing Settlement Total|5028510.18 |0.00
But when UFT runs the query, it returns error message while retrieving information:
print objRS.Fields(1)
Item cannot be found in the collection corresponding to the requested
name or ordinal
Printing err.number returns 0:
objConnection.Open "Provider=sqloledb.1; Server=server;User Id=userid; Password=password; Database=database"
Set objRS = objConnection.Execute(query)
print err.number
print objRS.state
print objConnection.state
0
0
0
The connection settings are 100% good, and even a simple query like SELECT * from [database].[schema].[table] and print recordset.fields(0) returns a valid result.
As far as I researched, problem might cause when the query has more than one column with same name, but that is not my case.
What can be the problem?

SQL query for finding first missing sequence string (prefix+no)

T-SQL query for finding first missing sequence string (prefix+no)
Sequence can have a prefix + a continuing no.
ex sequence will be
ID
-------
AUTO_500
AUTO_501
AUTO_502
AUTO_504
AUTO_505
AUTO_506
AUTO_507
AUTO_508
So above the missing sequence is AUTO_503 or if there is no missing sequence then it must return next sequence.
Also starting no is to specified ex. 500 in this case and prefix can be null i.e. no prefix only numbers as sequence.
You could LEFT JOIN the id numbers on shifted(+1) values to find gaps in sequential order:
SELECT
MIN(a.offsetnum) AS first_missing_num
FROM
(
SELECT 500 AS offsetnum
UNION
SELECT CAST(REPLACE(id, 'AUTO_', '') AS INT) + 1
FROM tbl
) a
LEFT JOIN
(SELECT CAST(REPLACE(id, 'AUTO_', '') AS INT) AS idnum FROM tbl) b ON a.offsetnum = b.idnum
WHERE
a.offsetnum >= 500 AND b.idnum IS NULL
SQLFiddle Demo
Using a recursive CTE to dynamically generate the sequence between the min and max of the ID Numbers maybe over complicated things a bit but it seems to work -
LIVE ON FIDDLE
CREATE TABLE tbl (
id VARCHAR(55)
);
INSERT INTO tbl VALUES
('AUTO_500'),
('AUTO_501'),
('AUTO_502'),
('AUTO_504'),
('AUTO_505'),
('AUTO_506'),
('AUTO_507'),
('AUTO_508'),
('509');
;WITH
data_cte(id)AS
(SELECT [id] = CAST(REPLACE(id, 'AUTO_', '') AS INT) FROM tbl)
,maxmin_cte(minId, maxId)AS
(SELECT [minId] = min(id),[maxId] = max(id) FROM data_cte)
,recursive_cte(n) AS
(
SELECT [minId] n from maxmin_cte
UNION ALL
SELECT (1 + n) n FROM recursive_cte WHERE n < (SELECT [maxId] from maxmin_cte)
)
SELECT x.n
FROM
recursive_cte x
LEFT OUTER JOIN data_cte y ON
x.n = y.id
WHERE y.id IS NULL
Check this solution.Here you just need to add identity column.
CREATE TABLE tbl (
id VARCHAR(55),
idn int identity(0,1)
);
INSERT INTO tbl VALUES
('AUTO_500'),
('AUTO_501'),
('AUTO_502'),
('AUTO_504'),
('AUTO_505'),
('AUTO_506'),
('AUTO_507'),
('AUTO_508'),
('509');
SELECT min(idn+500) FROM tbl where 'AUTO_'+cast((idn+500) as varchar)<>id
try this:
with cte as(
select cast(REPLACE(id,'AUTO_','') as int)-500+1 [diff],ROW_NUMBER()
over(order by cast(REPLACE(id,'AUTO_','') as int)) [rnk] from tbl)
select top 1 'AUTO_'+cast(500+rnk as varchar(50)) [ID] from cte
where [diff]=[rnk]
order by rnk desc
SQL FIddle Demo
Had a similar situation, where we have R_Cds that were like this R01005
;with Active_R_CD (R_CD)
As
(
Select Distinct Cast(Replace(R_CD,'R', ' ') as Int)
from table
where stat = 1)
select Arc.R_CD + 1 as 'Gaps in R Code'
from Active_R_CD as Arc
left outer join Active_R_CD as r on ARC.R_CD + 1 = R.R_CD
where R.R_CD is null
order by 1

SQL: How to update multiple fields so empty field content is moved to the logically last columns - lose blank address lines

I have three address line columns, aline1, aline2, aline3 for a street
address. As staged from inconsistent data, any or all of them can be
blank. I want to move the first non-blank to addrline1, 2nd non-blank
to addrline2, and clear line 3 if there aren't three non blank lines,
else leave it. ("First" means aline1 is first unless it's blank,
aline2 is first if aline1 is blank, aline3 is first if aline1 and 2
are both blank)
The rows in this staging table do not have a key and there could be
duplicate rows. I could add a key.
Not counting a big case statement that enumerates the possible
combination of blank and non blank and moves the fields around, how
can I update the table? (This same problem comes up with a lot more
than 3 lines, so that's why I don't want to use a case statement)
I'm using Microsoft SQL Server 2008
Another alternative. It uses the undocumented %%physloc%% function to work without a key. You would be much better off adding a key to the table.
CREATE TABLE #t
(
aline1 VARCHAR(100),
aline2 VARCHAR(100),
aline3 VARCHAR(100)
)
INSERT INTO #t VALUES(NULL, NULL, 'a1')
INSERT INTO #t VALUES('a2', NULL, 'b2')
;WITH cte
AS (SELECT *,
MAX(CASE WHEN RN=1 THEN value END) OVER (PARTITION BY %%physloc%%) AS new_aline1,
MAX(CASE WHEN RN=2 THEN value END) OVER (PARTITION BY %%physloc%%) AS new_aline2,
MAX(CASE WHEN RN=3 THEN value END) OVER (PARTITION BY %%physloc%%) AS new_aline3
FROM #t
OUTER APPLY (SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN value IS NULL THEN 1 ELSE 0 END, idx) AS
RN, idx, value
FROM (VALUES(1,aline1),
(2,aline2),
(3,aline3)) t (idx, value)) d)
UPDATE cte
SET aline1 = new_aline1,
aline2 = new_aline2,
aline3 = new_aline3
SELECT *
FROM #t
DROP TABLE #t
Here's an alternative
Sample table for discussion, don't worry about the nonsensical data, they just need to be null or not
create table taddress (id int,a varchar(10),b varchar(10),c varchar(10));
insert taddress
select 1,1,2,3 union all
select 2,1, null, 3 union all
select 3,null, 1, 2 union all
select 4,null,null,2 union all
select 5,1, null, null union all
select 6,null, 4, null
The query, which really just normalizes the data
;with tmp as (
select *, rn=ROW_NUMBER() over (partition by t.id order by sort)
from taddress t
outer apply
(
select 1, t.a where t.a is not null union all
select 2, t.b where t.b is not null union all
select 3, t.c where t.c is not null
--- EXPAND HERE
) u(sort, line)
)
select t0.id, t1.line, t2.line, t3.line
from taddress t0
left join tmp t1 on t1.id = t0.id and t1.rn=1
left join tmp t2 on t2.id = t0.id and t2.rn=2
left join tmp t3 on t3.id = t0.id and t3.rn=3
--- AND HERE
order by t0.id
EDIT - for the update back into table
;with tmp as (
select *, rn=ROW_NUMBER() over (partition by t.id order by sort)
from taddress t
outer apply
(
select 1, t.a where t.a is not null union all
select 2, t.b where t.b is not null union all
select 3, t.c where t.c is not null
--- EXPAND HERE
) u(sort, line)
)
UPDATE taddress
set a = t1.line,
b = t2.line,
c = t3.line
from taddress t0
left join tmp t1 on t1.id = t0.id and t1.rn=1
left join tmp t2 on t2.id = t0.id and t2.rn=2
left join tmp t3 on t3.id = t0.id and t3.rn=3
Update - Changed statement to an Update statement. Removed Case statement solution
With this solution, you will need a unique key in the staging table.
With Inputs As
(
Select PK, 1 As LineNum, aline1 As Value
From StagingTable
Where aline1 Is Not Null
Union All
Select PK, 2, aline2
From StagingTable
Where aline2 Is Not Null
Union All
Select PK, 3, aline3
From StagingTable
Where aline3 Is Not Null
)
, ResequencedInputs As
(
Select PK, Value
, Row_Number() Over( Order By LineNum ) As LineNum
From Inputs
)
, NewValues As
(
Select S.PK
, Min( Case When R.LineNum = 1 Then R.addrline1 End ) As addrline1
, Min( Case When R.LineNum = 2 Then R.addrline1 End ) As addrline2
, Min( Case When R.LineNum = 3 Then R.addrline1 End ) As addrline3
From StagingTable As S
Left Join ResequencedInputs As R
On R.PK = S.PK
Group By S.PK
)
Update OtherTable
Set addrline1 = T2.addrline1
, addrline2 = T2.addrline2
, addrline3 = T2.addrline3
From OtherTable As T
Left Join NewValues As T2
On T2.PK = T.PK
R. A. Cyberkiwi, Thomas, and Martin, thanks very much - these were very generous responses by each of you. All of these answers were the type of spoonfeeding I was looking for. I'd say they all rely on a key-like device and work by dividing addresses into lines, some of which are empty and some of which aren't, excluding the empties. In the case of lines of addresses, in my opinion this is semantically a gimmick to make the problem fit what SQL does well, and it's not a natural way to conceptualize the problem. Address lines are not "really" separate rows in a table that just got denormalized for a report. But that's debatable and whether you agree or not, I (a rank beginner) think each of your alternatives are idiomatic solutions worth elaborating on and studying.
I also get lots of similar cases where there really is normalization to be done - e.g., collatDesc1, collatCode1, collatLastAppraisal1, ... collatLastAppraisal5, with more complex criteria about what in excludeand how to order than with addresses, and I think techniques from your answers will be helpful.
%%phsloc%% is fun - since I'm able to create a key in this case I won't use it (as Martin advises). There was other stuff in Martin's stuff I wasn't familiar with too, and I'm still tossing them all around.
FWIW, here's the trigger I tried out, I don't know that I'll actually use it for the problem at hand. I think this qualifies a "bubble sort", with the swapping expressed in a peculiar way.
create trigger fixit on lines
instead of insert as
declare #maybeblank1 as varchar(max)
declare #maybeblank2 as varchar(max)
declare #maybeblank3 as varchar(max)
set #maybeBlank1 = (select line1 from inserted)
set #maybeBlank2 = (select line2 from inserted)
set #maybeBlank3 = (select line3 from inserted)
declare #counter int
set #counter = 0
while #counter < 3
begin
set #counter = #counter + 1
if #maybeBlank2 = ''
begin
set #maybeBlank2 =#maybeblank3
set #maybeBlank3 = ''
end
if #maybeBlank1 = ''
begin
set #maybeBlank1 = #maybeBlank2
set #maybeBlank2 = ''
end
end
select * into #kludge from inserted
update #kludge
set line1 = #maybeBlank1,
line2 = #maybeBlank2,
line3 = #maybeBlank3
insert into lines
select * from #kludge
You could make an insert and update trigger that check if the fields are empty and then move them.