I am trying to do a merge (insert and update) with the row_number function so that the ID_TRANS field are unique values in the remaining fields apply certain conditions. But when executing it I get a right parenthesis error, it is worth mentioning that I have modified and added parentheses and it remains unresolved.
MERGE INTO TBL_TRANSAC trans
USING (
SELECT ID_TRANS,
TIT,
BEN,
BAN,
CTA_EMI,
CTA_REC,
INST,
TYPE_TRANS,
TYPE_MOV,
CONC,
DATE_OPER,
MONT,
DIV,
ID_CONT
FROM (
SELECT T1.*
, ROW_NUMBER() OVER (PARTITION BY T1.ID_TRANS ORDER BY T1.ID_TRANS DESC)ENUMERADO
FROM (
SELECT
'speibco1_'||UPPER(REPLACE( AREA,' ',''))||
UPPER(REPLACE( FVALOR,' ',''))||
UPPER(REPLACE( CLAVE_RASTREO,' ','')) ,
TIT ,
BEN,
BAN_EM_DES,
REPLACE(UPPER(NO_TP_CTA_EMISOR),' ',''),
LTRIM(CTA_REC,'0'),
'BAN ACTINVER',
'CTA_EXTER',
'SPEI ENTRADA BCO',
CONC_2 ,
TO_DATE(TO_CHAR(FVALOR),'YYYY-MM-DD'),
REPLACE(REPLACE(IMPORTE,'-',''),' ',''),
'MXN' ,
LTRIM(CTA_REC,'0')||'0999'
FROM (SELECT *
FROM IBM_I2.I2_SPEI WHERE REPLACE(NO_TP_CTA_EMISOR,' ','') IS NOT NULL
AND ID_OPERACION='0007'
AND ESTATUS='06'
AND CTA_REC NOT IN ('70000997', '7909567'))
)
WHERE ENUMERADO=1
AND ID_TRANS IS NOT NULL
)SPEI
ON (
trans.ID_TRANS = SPEI.ID_TRANS
)
WHEN MATCHED THEN
UPDATE SET
ID_TRANS = SPEI.ID_TRANS,
TIT = SPEI.TIT ,
BEN= SPEI.BEN,
BAN=SPEI.BAN_EMISOR,
CTA_EMI=SPEI.CTA_EMI,
CTA_REC =SPEI.CTA_REC,
INST= SPEI.INST,
TYPE_TRANS=SPEI.TYPE_TRANS,
TYPE_MOV=SPEI.TYPE_MOV,
CONC=SPEI.CONC,
DATE_OPER=SPEI.DATE_OPER,
MONT=SPEI.MONT,
DIV= SPEI.DIV,
ID_CONT= SPEI.ID_CONT
WHEN NOT MATCHED THEN
INSERT (
ID_TRANS,
TIT,
BEN,
BAN,
CTA_EMI,
CTA_REC,
INST,
TYPE_TRANS,
TYPE_MOV,
CONC,
DATE_OPER,
MONT,DIV,
ID_CONT
)
VALUES
(
SPEI.ID_TRANS,
SPEI.TIT ,
SPEI.BEN,
SPEI.BAN_EMISOR,
SPEI.CTA_EMI,
SPEI.CTA_REC,
SPEI.INST,
SPEI.TYPE_TRANS,
SPEI.TYPE_MOV,
SPEI.CONC ,
SPEI.DATE_OPER,
SPEI.MONT,
SPEI.DIV ,
SPEI.ID_CONT
);
MARK ERROR THAT MISSING RIGHT PARENTESIS AFTER AND ID_TRANS IS NOT NULL
STILL PLACING THE PARENTESIS.
Looks like a closing parenthesis is missing, here:
)) --> here; should be 2, not only 1
WHERE ENUMERADO=1
AND ID_TRANS IS NOT NULL
Put parentheses and aliases to each of them, as well as the fields that are called in USING put aliases, and that worked.
FROM (SELECT *
FROM IBM_I2.I2_SPEI WHERE REPLACE(NO_TP_CTA_EMISOR,' ','') IS NOT NULL
AND ID_OPERACION='0007'
AND ESTATUS='06'
AND CTA_REC NOT IN ('70000997', '7909567')
)
)T1
)T2
WHERE ENUMERADO=1
AND ID_TRANS IS NOT NULL
)SPEI
ON (
trans.ID_TRANS = SPEI.C1_ID_TRANS
)
Related
Before I go any further please mind that I am not well experienced with SQL.
I have one query that is getting a single value (netto value) such as:
WITH cte_value_net AS (
SELECT
nvl(min(value_net),0) as value_net
FROM (
SELECT
i.serial as serial,
nvl(lag(i.value_net) OVER (PARTITION BY i.serial ORDER BY i.month), i.value_net) as value_net
FROM
inventory i
WHERE
i.ctypde IN (
SELECT
ctypde
FROM
appar ap
WHERE
ap.serial = in_serial -- this is the variable I want to set
)
AND
i.month IN (to_char(add_months(sysdate, -1), 'YYYYMM'), to_char(add_months(sysdate, -2), 'YYYYMM'))
AND
i.serial = in_serial -- this is the variable I want to set
) vn
GROUP BY vn.serial
)
In here I have to feed in the variable in_serial that I thought I could get from another subquery such as:
SELECT
(SELECT * FROM cte_value_net) AS value_net
FROM (
SELECT
lap.serial AS in_serial
FROM
applap lap
)
but I can not wrap my head around it why this in_serial is not visible to my custom CTE. Could someone explain me how can I propagate the value from subquery like this?
The error I am obviously getting is:
SQL Error [904] [42000]: ORA-00904: "IN_SERIAL"
Unfortunately I do not have any sample data. What I want to achieve is that I could feed in the returned in_serial from main subquery to my CTE.
Before I can get value_net I need my main query to return the in_serial, otherwise I do not have access to that value.
The trick I use is to produce an extra CTE that I usually call params that includes a single row with all computed parameters. Then, it's a matter of performing a CROSS JOIN with this CTE in any other CTE, subquery or main query, as needed.
For example:
with
params as ( -- 1. Create a CTE that returns a single row
select serial as in_serial from applap
),
cte_value_net AS (
select ...
from inventory i
cross join params -- 2. cross join against the CTE anywhere you need it
where ...
and i.serial = params.in_serial -- 3. Use the parameter
)
select ...
First, your second query is not syntactically correct, as there's a ',' before the FROM. You can write your query like this:
WITH cte_value_net AS (
SELECT
serial, nvl(min(value_net),0) as value_net
FROM (
SELECT
i.serial as serial,
nvl(lag(i.value_net) OVER (PARTITION BY i.serial ORDER BY i.month), i.value_net) as value_net
FROM
inventory i
WHERE
i.ctypde IN (
SELECT
ctypde
FROM
appar ap
WHERE
ap.serial = i.serial
)
AND
i.month IN (to_char(add_months(sysdate, -1), 'YYYYMM'), to_char(add_months(sysdate, -2), 'YYYYMM'))
) vn
GROUP BY vn.serial
)
select ...
from cte_value_net s join applap lap on (lap.serial=s.serial)
(adjust query to your schema ....)
I'm stuck on something simple. I have to work with this type of table :
CREATE TABLE FORM (
ID_FORM INT,
ACT_1 VARCHAR2 (10),
ACT_2 VARCHAR2 (10),
ACT_3 VARCHAR2 (10),
ACT_4 VARCHAR2 (10),
DESC_1 VARCHAR2 (10),
DESC_2 VARCHAR2 (10),
DESC_3 VARCHAR2 (10),
DESC_4 VARCHAR2 (10),
ECH_1 INT,
ECH_2 INT,
ECH_3 INT,
ECH_4 INT
);
INSERT INTO FORM VALUES ('1','A1','A2','A3',null,'D1','D2','D3',null,'2','12','6',null);
INSERT INTO FORM VALUES ('2','A1','A1','A3',null,'D1','D2','D1',null,'2','2','2',null);
INSERT INTO FORM VALUES ('3','A3','A3','A1',null,'D4','D4','D1',null,'2','2','12',null);
I want to create a function that return for one ID_FORM (PRIMARY KEY) the number of distinct values group by / concatanate cols like :
ACT_1|| DESC_1|| ECH_1 -> presta1
ACT_2|| DESC_2|| ECH_2 -> presta2
ACT_3|| DESC_3|| ECH_3 -> presta3
ACT_4|| DESC_4|| ECH_4 -> presta4
And i have to "COUNT DISTINCT" item
For example for :
select
ACT_1|| DESC_1|| ECH_1 as presta1,
ACT_2|| DESC_2|| ECH_2 as presta2,
ACT_3|| DESC_3|| ECH_3 as presta3,
ACT_4|| DESC_4|| ECH_4 as presta4
from FORM;
PRESTA1 PRESTA2 PRESTA3 PRESTA4
A1D12 A2D212 A3D36 - (Function have to return 3)
A1D12 A1D22 A3D12 - (Function have to return 3)
A3D42 A3D42 A1D112 - (function have to return 2)
Note that in reality the table is much larger and extends up to 8 "presta" (till ACT_8, DESC_8, ECH_8)
Someone can help me ?
You can unpivot your column groups to rows and do COUNT(DISTINCT ) on them.
Fiddle
select
id_form,
count(distinct act || desc_ || ech) as cnt
from form
unpivot (
(act, desc_, ech) for presta_no in (
(act_1, desc_1, ech_1) as '1',
(act_2, desc_2, ech_2) as '2',
(act_3, desc_3, ech_3) as '3',
(act_4, desc_4, ech_4) as '4'
)
) p
group by id_form
You'd better normalize the table to make queries simple. If it is not an option you may unpivot it first in the query. Or proceed with lateral join
select ID_FORM, n
from FORM f
cross apply (
select count(*) n
from (
select f.act_1 || f.DESC_1 || f.ECH_1 presta from dual
union
select f.act_2 || f.DESC_2 || f.ECH_2 from dual
union
select f.act_3 || f.DESC_3 || f.ECH_3 from dual
union
select f.act_4 || f.DESC_4 || f.ECH_4 from dual
)
where presta is not null
)
I think the following query will actually answer your question:
WITH destruct AS
(
SELECT ID_FORM,
SUBSTR(COL_TYPE, 1, INSTR(COL_TYPE, '_')-1) AS COL_TYPE,
SUBSTR(COL_TYPE, INSTR(COL_TYPE, '_')+1) AS COL_NUM,
VAL
FROM (SELECT ID_FORM, ACT_1, ACT_2, ACT_3, ACT_4, DESC_1, DESC_2, DESC_3, DESC_4,
TO_CHAR(ECH_1) AS ECH_1, TO_CHAR(ECH_2) AS ECH_2,
TO_CHAR(ECH_3) AS ECH_3, TO_CHAR(ECH_4) AS ECH_4
FROM FORM
/*WHERE id_form = :1*/)
UNPIVOT INCLUDE NULLS (VAL FOR COL_TYPE IN (ACT_1, ACT_2, ACT_3, ACT_4,
DESC_1, DESC_2, DESC_3, DESC_4,
ECH_1, ECH_2, ECH_3, ECH_4))
)
SELECT da.id_form, da.val, dd.val, de.val
FROM destruct da
INNER JOIN destruct dd ON da.id_form = dd.id_form AND da.col_num = dd.col_num AND dd.col_type = 'DESC'
INNER JOIN destruct de ON da.id_form = de.id_form AND da.col_num = de.col_num AND de.col_type = 'ECH'
WHERE da.col_type = 'ACT';
This is actually a bit more complicated than it needs to be due to the ECH columns being of a different type. If you want it for just one ID_FORM you can uncomment the WHERE clause and use the bind variable from your function.
Edit: Adding a DBFiddle (Link)
Precompute PRESTA columns (8 columns is not too much IMHO) and count distinct values in correlated subquery on some collection of that columns. (I used built-in sys.ku$_vcnt here, some consider it as antipattern, you can easily create your own nested table.)
with pr(PRESTA1, PRESTA2, PRESTA3, ...) as (
select ACT_1|| DESC_1|| ECH_1, ... (your concatenating expression)
from form
)
select pr.*
, (select count(distinct column_value)
from table(sys.ku$_vcnt(PRESTA1, PRESTA2, PRESTA3, ...))
)
from pr
My table looks like this
NAME BRAND REFERENCE COMMENTS <-Expected output
-------------------------------------------------
Gu Skirt 101128 Pants
Cci Pants 101127 Pants
Cha Skirt paired paired
Gu Pants 101128 Skirts
Nel Skirt nonpaired UNIQUE
Gir Pants 101188 Skirt
Baud Skirt dropped DROPPED
Le Pants paired PAIRED
Gir Skirt 101188 101178
Vis Socks blanks
Cci Skirts 101127 Skirts
I wonder what code to use to get the Comments result.
First reference in NUMBERS should be paired. If reference numbers match, return value should be the Brand counterpart.
If reference is in Character, they have to fall under if statements: IF character is Nonpaired return value should be unique, dropped for dropped and so on. If the reference is blanks no change.
Is this possible?
Thank you so much.
You can use common table expressions to break down the problem which can help with maintaining the code.
I didn't use lag/lead because you only have two rows in the pair, so numbering the rows and joining the table to itself felt quicker and easier to follow.
Here's the code I've used to answer and test your question;
create table #source
(
[NAME] varchar(200),
[BRAND] varchar(200),
[REFERENCE] varchar(200)
);
insert into #source values
('Gu','Skirt','101128'),
('Cci','Pants','101127'),
('Cha','Skirt','paired'),
('Gu','Pants','101128'),
('Nel','Skirt','nonpaired'),
('Gir','Pants','101188'),
('Baud','Skirt','dropped'),
('Le','Pants','paired'),
('Gir','Skirt','101188'),
('Vis','Socks',''),
('Cci','Skirts','101127'),
('Le','Socks','101188'),
('Uno','Socks','101101');
select * from #source;
with cteNumericRef as
(
select [NAME],[BRAND],[REFERENCE]
from #source
where ISNUMERIC([REFERENCE]) = 1
)
, cteCheckRow as
(
select [REFERENCE],
'CHECK' as [COMMENT]
from cteNumericRef
group by [REFERENCE]
having count(*) <> 2
)
, ctePairedRow as
(
select
num_ref.[NAME]
, num_ref.[BRAND]
, num_ref.[REFERENCE]
, row_number() over (partition by num_ref.[REFERENCE] order by num_ref.[NAME]) as [Pair_Num]
from cteNumericRef num_ref
left join cteCheckRow check_row
on check_row.[REFERENCE] = num_ref.[REFERENCE]
where check_row.[REFERENCE] is null
)
, cteTextRow as
(
select [NAME],[BRAND],[REFERENCE],
case [REFERENCE]
when 'paired' then 'PAIRED'
when 'nonpaired' then 'UNIQUE'
when 'dropped' then 'DROPPED'
when '' then ''
else 'CHECK' end as [COMMENT]
from #source
where ISNUMERIC([REFERENCE]) <> 1
)
select
left_row.[NAME]
, left_row.[BRAND]
, left_row.[REFERENCE]
, right_row.[BRAND] as [COMMENTS]
from ctePairedRow left_row
inner join ctePairedRow right_row
on left_row.[REFERENCE] = right_row.[REFERENCE]
and left_row.[Pair_Num] <> right_row.[Pair_Num]
union all
select
num_ref.[NAME]
, num_ref.[BRAND]
, num_ref.[REFERENCE]
, check_row.[COMMENT]
from cteNumericRef num_ref
inner join cteCheckRow check_row
on check_row.[REFERENCE] = num_ref.[REFERENCE]
union all
select
[NAME]
, [BRAND]
, [REFERENCE]
, [COMMENT]
from cteTextRow;
drop table #source
SELECT Name,
Brand,
Reference,
CASE WHEN Reference = 'Paired' THEN 'Paired'
WHEN Reference = 'nonpaired' THEN 'Unique'
WHEN Reference = 'dropped' THEN 'DROPPED'
WHEN Reference = ' ' THEN 'blanks'
WHEN Reference = Next_Ref AND rownum = 1 THEN next_brand
WHEN Reference = Prev_Ref AND rownum = 2 THEN prev_brand
END AS Comments
FROM
(
SELECT Name,
Brand,
Reference,
LAG( Reference, 1 )OVER PARTITION BY ( Reference ORDER BY Brand ) AS Prev_Ref,
LEAD( Reference, 1 )OVER PARTITION BY ( Reference ORDER BY Brand ) AS Next_Ref,
LAG( Brand, 1 ) OVER PARTITION BY ( Reference ORDER BY Brand ) AS Prev_Brand,
LEAD( Brand, 1 ) OVER PARTITION BY ( Reference ORDER BY Brand ) AS Next_Brand,
ROW_NUMBER( ) OVER PARTITION BY ( Reference ORDER BY Brand ) AS rownum
FROM Data
);
I'm creating a view in MariaDB and i'm having trouble making it work for a couple of fields. Currently this is working:
( SELECT DISTINCT IFNULL(grades.`grade`,'No Grade')
FROM `table` grades
WHERE userinfo.`id` = grades.`id`
AND grades.`Item Name` = 'SOMEINFO'
) 'SOMENAME',
But i need to add a select where the 'No grade' is, in the following form
( SELECT DISTINCT IFNULL( grades.`grade`,
SELECT IF( EXISTS
( SELECT *
FROM `another_table`
WHERE userid = 365
AND courseid = 2
), 'Enrolled', 'Not enrolled'
)
)
FROM `table` grades
WHERE userinfo.`id` = grades.`id`
AND grades.`Item Name` = 'SOMEINFO'
) 'SOMENAME',
i know that
SELECT IF( EXISTS( SELECT *
FROM `another_table`
WHERE userid = 365
AND courseid = 2
),
'Enrolled', 'Not enrolled'
)
is working too, but now the whole thing it's giving me an error, so any suggestions would be greatly appreciated
Thanks
This looks like a subquery:
(SELECT DISTINCT IFNULL(grades.`grade`,
SELECT IF( EXISTS (SELECT *
FROM `another_table`
WHERE userid = 365 AND courseid = 2
), 'Enrolled', 'Not enrolled'
)
)
FROM `table` grades
WHERE userinfo.`id` = grades.`id` AND
grades.`Item Name` = 'SOMEINFO'
) as SOMENAME,
You are using a subquery that returns two columns in a position where a scalar subquery is expected. A scalar subquery returns one column in at most one row.
Unfortunately, there is no easy way to do what you want in MySQL, because of the restrictions on views. I would advise you to rewrite the logic so the exists is handled using a left join in the from clause.
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.