Auto Generated Serial Number using Stored Procedure - sql

I want to create a procedure which would create a serial number using a stored procedure.
I have three tables:
Table 1:
create table ItemTypes
(
ItemTypeID int not null primary key,
ItemType varchar(30)
)
Table 2:
create table ItemBatchNumber
(
ItemBatchNumberID int not null primary key,
ItemBatchNumber varchar(20),
ItemType varchar(30),
)
Table 3:
create table ItemMfg
(
ManufactureID int not null primary key,
ItemBatchNumberID int foreign key references ItemBatchNumber(ItemBatchNumberID),
SerialNumber varchar(10),
MfgDate datetime
)
For each Item Type there are several Item batch number.
Now, first 3 digit of serial no is xyz. 4 digit of serial no should be Item Type(e.g if Item type is 'b' then serial no should be xyzb).
5 digit of serial no should be like this:
In a day, for first Item batch number of a Item type- 5th digit should be 1 and it will remain 1 for that day.For the next Item batch number it should be 2 and it will remain 2 for that day.
For next day same rule applied.
e.g suppose 'b' Item Type has 3 Item batch number WB1,WB2,WB3. If today someone select WB2(Item batch number) of 'b' Item Type first then Serial No should be xyzb1 and it will remain xyzb1 for today for WB2. Now if someone select WR1 next then Serial No should be xyzb2 for today. Tomorrow which Item batch number of 'b' Item type will be selected first, for that batch number and that type serial no should be xyzb1. Same rule applied for other item type.
I have tried till now:
create procedure Gen_SerialNumber
(
#ManufactureID int,
#IitemType varchar(30),
#ItemBatchNumberID int,
#Date datetime,
#SerialNumber out,
#fifthDigit int out
)
AS
Begin
set #IitemType=(Select ItemType from ItemBatchNumber where ItemBatchNumber=#ItemBatchNumber)
Declare #SerialNumber1 varchar(20)
Set #SerialNumber1= 'xyz'+''+#IitemType+''+CAST( (Select COUNT(distinct ItemBatchNumber)from ItemBatchNumber
where ItemType=#IitemType) as varchar (10) )
Set #fifthDigit=SUBSTRING(#SerialNumber1,5,1)
IF EXISTS(SELECT SerialNumber FORM ItemMfg WHERE SerialNumber=null or SerialNumber!=#SerialNumber)
SET #fifthDigit=1
IF EXISTS(SELECT mfgDate,ItemBatchNumberID FROM ItemMfg WHERE mfgDate=#Date and ItemBatchNumberID=#ItemBatchNumberID)
SET #fifthDigit=1
ELSE
SET #fifthDigit=#fifthDigit+1
SET #SerialNumber=('xyz'+''+#ItemType+''+cast(#fifthdigit as varchar(2)))
INSERT INTO ItemMfg VALUES(#ItemType,#ItemBatchNumberID,#SerialNumber,#Date)
END
I am new to SQL. 4rth digit of SN is generated correctly from my code. I am facing problem on how to increment the value of fifth digit checking with dates when next different item batch number of a same item type or different item type is used. Please let me know if you have any doubt. Thanks in advance.

A couple of concerns with your question: I am confused by the appearance of the WireBatchNumber column in your stored procedure, as that is not included in the table definition you provided. Secondly, the last #ItemType (right before the end command) is misspelled.
I think the challenge here is that you need your stored procedure increment a variable across batches and to "start over" each day. That would suggest to me that you need the procedure to
1. Track the last time it was run and see if it was today or not.
2. Track how many times it has been run today.
It is not a very beginner level knowledge type of task, but there is a way, apparently: how to declare global variable in SQL Server..?. Using the type of variable mentioned in this link, you could set up some conditional structures that compare a date variable to today using the DateDiff() function, changing the date variable and resetting your counters if they the two dates are on different days, then incrementing a counter for the item batch number and using this counter to provide the fifth digit.

Let's populate some data:
ItemTypes:
ItemTypeID ItemType
1 a
2 b
3 c
ItemBatchNumber:
ItemBatchNumberID ItemBatchNumber ItemType
...
11 WB1 b
22 WB2 b !
33 WB3 b !!
44 WB1 c
55 WB2 c !
66 WB3 c !!
77 WB3 c !!
...
ItemMfg:
ManufactureID ItemBatchNumberID MfgDate
111 22 2015-03-01 7:00 -> xyzb1
222 11 2015-03-01 8:00 -> xyzb1
333 22 2015-03-01 9:00 -> xyzb2
444 33 2015-03-02 5:00 -> xyzb1
555 33 2015-03-02 6:00 -> xyzb2
666 11 2015-03-02 7:00 -> xyzb1
777 33 2015-03-02 8:00 -> xyzb3
888 11 2015-03-02 9:00 -> xyzb2
999 22 2015-03-02 9:35 -> xyzb1
I see some inappropriate things - it does not necessary means there are mistakes.
Sorry, I do not know real business rules - they may explain things differently.
I assume the simplest and most usable logic.
ItemTypes - is looks like lookup table. But you do not use ItemTypeID, instead you use it's value (a,b,c) as unique code.
So table should looks like this:
ItemType(PK) ItemTypeDescr
a Type A
b Most Usable Type B
c Free text for type C
ItemBatchNumber - match table - define matches between batches and ItemTypes.
It may have data as marked with "!", and this is valid.
To avoid 77 need add some unique index or set PK on ItemBatchNumber+ItemType.
But in any case sets as 22,55 and 11,44.. are normaly expected. So your SP will fails.
Here you will get an error.
Here query may return multipple rows (22, 55):
set #IitemType=(Select ItemType from ItemBatchNumber where ItemBatchNumber=#ItemBatchNumber)
alternatively:
Select #IitemType = ItemType from ItemBatchNumber where ItemBatchNumber=#ItemBatchNumber
in case of multipple rows it will return last one.
But anyway it is not correct - if #ItemBatchNumber = 'WB2' which value is expected 'b' or 'c'?
errors:
...
... and ItemTypeID=#IitemType ...
ItemTypeID is int;
#IitemType is char ('b') - what do you expect?
...
MfgDate=#Date
Dates '2015-03-02 5:00' and '2015-03-02 7:00' are not the same, but in the same day.
...
...from ItemBatchNumber,ItemMfg
where MfgDate=#Date
and ItemBatchNumber=#ItemBatchNumber
and ItemTypeID=#IitemType
even if ItemBatchNumber will return one row, and date will not count time, it will return ALL batches from ItemMfg from one day.
you need to do proper join.
...
Select COUNT(distinct ItemBatchNumber)
you always will need (count() + 1), and not a distinct
I am not sure, when you need to generate SN:
a. at the moment when (before) you ADD new ItemMfg, then need to check for current day.
b. for any existed ItemMfg row (for 555), then you need to exclude from count() all rqws after 555.
That's how query may looks:
a. (on adding new ItemMfg-row - pass values used for creation ItemMfg-row)
create procedure AddNewItemMfg -- ...and generate SN
(
#ItemBatchNumberID int,
#MfgDate datetime -- pass getdate()
) AS Begin
-- calc 5th digit:
declare #fifthDigit int;
select
#fifthDigit = count(*) + 1
from ItemBatchNumber AS bb
inner join ItemMfg ii ON ii.ItemBatchNumberID = bb.ItemBatchNumberID
where bb.ItemBatchNumberID = #ItemBatchNumberID -- single ItemBatchNumber-row to get ItemType
and ii.MfgDate <= #MfgDate -- all previous datetimes
and cast(ii.MfgDate as date) = cast(#MfgDate as date) -- same day
-- ManufactureID is Identity (i.e. autoincremented)
INSERT INTO ItemMfg (ItemBatchNumberID, MfgDate, SerialNumber)
SELECT #ItemBatchNumberID
, #MfgDate
, 'xyz' + bb.ItemType + cast(#fifthDigit as varchar(5))
FROM ItemBatchNumber bb
WHERE bb.ItemBatchNumber = #ItemBatchNumber
;
end
b. for any already existed ItemMfg-row
create procedure GenerateSNforExistedItemMfg
(
#ManufactureID int
) AS Begin
-- generate SN - same as previous but in single query
declare #SN varchar(10);
Select #SN = 'xyz'
+ bb.ItemType
+ cast(
select count(*) + 1
from ItemMfg mm -- single row from mm
inner join ItemBatchNumber AS bb -- single row from bb
ON bb.ItemBatchNumberID = mm.ItemBatchNumberID
inner join ItemMfg ii -- many matched rows
ON ii.ItemBatchNumberID = bb.ItemBatchNumberID
where mm.ManufactureID = #ManufactureID -- single row from mm
and ii.MfgDate <= mm.MfgDate -- all previous datetimes
and cast(ii.MfgDate as date) = cast(mm.MfgDate as date) -- same day
as varchar(5))
FROM ItemBatchNumber AS bb
INNER JOIN ItemMfg ii ON ii.ItemBatchNumberID = bb.ItemBatchNumberID
WHERE ii.ManufactureID = #ManufactureID
-- update SN
UPDATE ItemMfg SET
SerialNumber = #SN
WHERE ii.ManufactureID = #ManufactureID;
end

Related

How can I get the last row without order by and assign a value to a variable?

I have a query that is within a View so I can not use order by . I have a column called Course that column is an Int Column and it can have many repeating values . There is also a column called status that status column is also an Int and it will have unique values . I am trying to create a query where we can get the last row of a particular Course and see if the Status is 2 if yes then add 1 to #MyValue if not then add 0 to the variable .I have an ID column which is the primary key, without order by I am having a tough time figuring this one out .
MyValue is a smallint and we simply assign the value
CourseNumber is a Int and a table can have many (Course) #CourseNumber with the same number
There will only be 1 combination of CourseNumber and Status . We can have many CourseNumbers with the same number etc 120 however each one will have a different Status
What I want to do with the query below is get the last record of #CourseNumber we have an ID column and check if the status of the last record of #CourseNumber is equal to 2 . If it's equal to 2 then assign the value 1 to #MyValue and if it is not equal to 2 then assign the value 0 .
SELECT #MyValue =(SELECT count(*) FROM MyTasks as MT WHERE MT.Course = #CourseNumber And MT.status=2)
Sample: ID Course Status
1 23 4
2 23 5
3 23 2
4 23 1
Assuming that was the database table the Course is [#CourseNumber] is 23 . We would want to get the last row of the Course number which is [4] and we would want the status which is [1] since the status is not 2 for that last row we would just return a 0 and we would only return a 1 if the last row of the course number has a status of 1 . This is a sql function inside of a view . I try to leave out some of things that might not be necessary since it is a large View and function .
You want to self join to the table to determine the maximum ID value to find the record you want. You say add 1 to #MyValue and later you say to set #MyValue = 1. This will add 1 to #MyValue. If you want #MyValue = 1, change the case statement removing the #MyValue parameter.
DECLARE #MyValue INT = 0
, #CourseNumber INT = 23
SELECT #MyValue = CASE WHEN t0.Status = 2 THEN #MyValue + 1 ELSE #MyValue END
FROM MyTasks t0
JOIN
(
SELECT Couse
, MAX(ID) MAXID
FROM MyTasks
WHERE Course = #CourseNumber
) t1 ON t0.Course = t1.Course AND t0.ID = t1.MAXID

How can I flag the earliest of overlapping records?

I have a dataset where I need to pick out and keep records that have no overlapping time frames, and for those that do overlap, keep the earliest record.
I have been able to successfully picked out the records that have no overlapping time frames with the below code:
IF OBJECT_ID('tempdb..#overlaps') IS NOT NULL DROP Table #overlaps
SELECT
CASE WHEN EXISTS(SELECT 1 FROM #service r2
WHERE r2.client_ID = r1.client_ID
AND r2.service_ID <> r1.service_ID
AND r1.service_start_date <= r2.service_end_date
AND r2.service_start_date <= r1.service_end_date)
THEN 1
ELSE 0
END AS Overlap
,*
into #overlaps
FROM #services r1
This produces the below for an example client:
Overlap client_ID service_ID service_start_date service_end_date
1 12345 123 27-Oct-2009 03-Jan-2013
1 12345 124 27-Dec-2012 19-Mar-2013
1 12345 125 18-Mar-2013 04-Jun-2014
1 12345 126 29-Jun-2014 28-Apr-2017
1 12345 127 23-Jun-2014 14-Aug-2014
1 12345 128 27-Apr-2015 07-Nov-2015
1 12345 129 01-Aug-2015 01-Dec-2015
0 12345 132 01-Jul-2017 09-Dec-2017
0 12345 133 02-Jan-2018 20-Jan-2018
0 12345 134 03-May-2018 05-Jun-2018
What I want to do, is for where overlap = 1, add a column to flag if that record is the first record of an overlapping "set", first in terms of the start date. The service_ID is not actually sequential, I just replaced it to be as dummy data.
So in the above case, record #1 should be flagged a 1 because it has the earliest start of the service compared to its overlapped service record #2 which started later, so record #2 would be flagged a 0, the same for record #3 (ie. flagged as a 0). Going on, record #4 should be flagged as a 1, as it overlaps the ones records below it.
In terms of the final product, I eventually want to just show any non-overlapping periods, and the earliest/first record for the records that do overlap So in the above scenario, records #1,4, 8,9,10 would remain and the rest would be removed. Each record should remain it's own record though, they should not be "pivoted" up into a continuous record.
In other words, what I need to flag are the earliest record that started where there is more than one active service occurring in parallel.
EDIT:
So for example, client has 4 services: Service A started Jan 1 - July 31, Service B Started Feb 1 ended August 1, Service C started September 1 ended Oct 1, Service D started Nov 1 ended Dec 1...Service A should be flagged as 1, Service B which started while Service A was still active should be flagged 0, Service C started without any service being active will be flagged as 1, same as Service D
I think the flag would be:
SELECT (CASE WHEN NOT EXISTS (SELECT 1
FROM #service r2
WHERE r2.client_ID = r1.client_ID AND
r2.service_ID <> r1.service_ID AND
r1.service_start_date <= r2.service_end_date AND
r2.service_start_date < r1.service_end_date
)
THEN 1
ELSE 0
END) AS First_Overlap;
Notes:
This doesn't actually check for an overlap. I left that out, because you can use the overlaps flag for the check, or include the exists query.
The only difference is < versus <= for the overlap check on the start date.
This might not work as you want when the period of overlap has multiple records beginning at the same time.
Also, I suspect you are trying to solve a gaps-and-islands problem. Using multiple temporary tables and the logic that you are using is unnecessary. You might want to ask another question about the entire problem you want to solve, rather than this one facet.
Its difficult to read your exact goal here, but if you're looking to flag based on the service_start_date, when Overlap = 1. This would suffice.
;WITH CTE (Overlap, client_ID, service_ID, service_start_date) AS (
SELECT * FROM (
VALUES
('1','12345','123','10/27/2009'),
('1','12345','124','12/27/2012'),
('1','12345','125','3/18/2013'),
('1','12345','126','6/29/2014'),
('1','12345','127','6/23/2014'),
('1','12345','128','4/27/2015'),
('1','12345','129','8/1/2015'),
('0','12345','132','7/1/2017'),
('0','12345','133','1/2/2018'),
('0','12345','134','5/3/2018')
) AS A (Overlap, client_ID, service_ID, service_start_date)
)
SELECT CTE.Overlap,
CTE.client_ID,
CTE.service_ID,
CTE.service_start_date,
t2.Result
FROM CTE
LEFT JOIN (
SELECT '1' AS Result,
t2.client_ID,
MIN(t2.service_start_date) AS service_start_date
FROM CTE t2
WHERE t2.Overlap = '1'
GROUP BY client_ID
) t2 ON CTE.client_ID = t2.client_ID
AND CTE.service_start_date = t2.service_start_date
ORDER BY service_ID
This also does not account for anything other than flagging the first Overlap by service_start_date. For instance, if you wanted to flag those that aren't first as 0's, that would need to be added.
UPDATE #overlaps SET IsFirst=1
FROM
(SELECT overlap, client_id client_id, service_start_date service_start_date, service_end_date service_end_date, min(service_id) service_id
FROM #overlaps
WHERE overlap=1
group by overlap, client_id, service_start_date, service_end_date) a
where #overlaps.client_id = a.client_id and #overlaps.service_id = a.service_id
Edit
#marshymell0 - I think I'm understanding what you want. Writing this as a query is pretty tricky, so I'm using a cursor instead. In the section where I have the line PRINT #service_start_date_prev, is where you would update the flag column that determines if the record is the first in the overlapping set.
DECLARE #overlap_prev int, #client_id_prev int, #service_id_prev int
DECLARE #overlap_next int, #client_id_next int, #service_id_next int
DECLARE #service_start_date_prev datetime, #service_end_date_prev datetime
DECLARE #service_start_date_next datetime, #service_end_date_next datetime
DECLARE #part_of_set int = 0
DECLARE o_cursor CURSOR
FOR SELECT overlap, client_id, service_id, service_start_date, service_end_date
FROM #overlaps where overlap=1
ORDER BY service_start_date
OPEN o_cursor
FETCH NEXT FROM o_cursor
INTO #overlap_next, #client_id_next, #service_id_next, #service_start_date_next, #service_end_date_next
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#service_start_date_prev IS NOT NULL)
BEGIN
IF (#part_of_set = 0 AND #service_start_date_prev <= #service_end_date_next AND #service_start_date_next <= #service_end_date_prev)
BEGIN
PRINT #service_start_date_prev
SET #part_of_set = 1
END
ELSE
SET #part_of_set = 0
END
SET #overlap_prev = #overlap_next
SET #client_id_prev = #client_id_next
SET #service_id_prev = #service_id_next
SET #service_start_date_prev = #service_start_date_next
SET #service_end_date_prev = #service_end_date_next
FETCH NEXT FROM o_cursor
INTO #overlap_next, #client_id_next, #service_id_next, #service_start_date_next, #service_end_date_next
END
CLOSE o_cursor;
DEALLOCATE o_cursor;

Stored Procedure/Function Logic for Summing of account balances

Version B C D output Account number Balance
----------------------------------------------------------------
2 1283 1303 0 4071 1 10
2 1283 1304 0 4072 2 20
3 1283 4068 1303 4071 1 30
3 1283 4069 1304 4072 4 40
4 1283 4071 4068 4071 5 -50
4 1283 4072 4069 4072 2 90
Version,B,C,D are columns present in all_details table.Column "Output" is the desired output i wish to achieve and i wish to store all the above columns in a table until output
How in the first line of Output i placed 4071 is
1) i took 1303 in column C and then looked into column D
2) then it is again referring to 4068 in column C
3) Then i took 4068 and it is refering to 4071 in column C its like a linkage
I'm using column B as it is related information to other columns.
i need a another column output so that i can identify related links and sum up balances.For example
I'll sum up related links 1303,4068,4071 balances Group by Output i'll get 10+40 = 50 for account 1 and -50 for account 5 corresponding to 4071
So from what I am understanding, you need to have something that recursively finds the last linked number, for a given number. These links exists between your Column C and Column D.
I am assuming that Column B is a grouping type number, but I am certain that you might be able to figure out how to adjust the function to return what you need it to return.
What you will need to do is build a SQL function that will iterate through your table and follow the links until it can find no more links. Details and example follow below as to how one can do that.
So firstly the building up of the sample data, as you presented them (NOTE this creates a table on your database, be careful!)
-- Building testing data
if exists (select 1
from sys.objects
where name = 'versionhistory'
and type = 'U')
begin
drop table versionhistory
end
create table versionhistory
( versionno int,
colB int,
colC int, -- Current Value
colD int ) -- Previous value
insert versionhistory
( versionno,
colB,
colC,
colD )
values -- B C D
( 2, 1283, 1303, 0),
( 2, 1283, 1304, 0),
( 3, 1283, 4068, 1303),
( 3, 1283, 4069, 1304),
( 4, 1283, 4071, 4068),
( 4, 1283, 4072, 4069)
go
Now we need to create the function that will iterate through the tables records, follow the links between the two columns until it can find no more links, then return the last linked value.
-- Create the function that will get the last entry for a give number
if exists (select 1 from sys.objects where name = 'f_get_last_ver' and type = 'FN')
begin
drop function f_get_last_ver
end
go
create function f_get_last_ver
( #colB int,
#colC int )
returns int
as
begin
declare #nextColC int,
#lastColC int
-- Initial check if there is a 'next' version
select #nextColC = isnull((select vh.colC
from versionhistory vh
where vh.colB = #colB
and vh.colD = #colC), 0)
-- This will handle the loop until there are no more entries linked
while isnull(#nextColC, 0) <> 0
begin
-- Store our last value for return purposes
select #lastColC = #nextColC
-- Get our next version number that is linked
select #nextColC = isnull((select vh.colC
from versionhistory vh
where vh.colB = #colB
and vh.colD = #nextColC), 0)
end
-- Return our last value, otherwise if no linkage was found, return the input
return isnull(#lastColC, #colC)
end
go
And finally here you have the usage of the function.
-- Example usage
select dbo.f_get_last_ver(1283, 1303), -- returns 4071
dbo.f_get_last_ver(1283, 1304) -- returns 4072
Remember to clean up your database when done testing/experimenting with this
I hope that the comments inside the function will explain enough of what is happening, but if something is unclear, ask away.
P.S. Please rename your columns and variables in your actual code into more meaningful column names and variables, since B, C, D doesn't really explain what they are used for.

Comparing two tables for each column of each row and result as log variable

I need to compare two tables in each row. the tables are as follows:-
Table a:
ID First_Name Last_name Birthdate
1 Shradha Deshkmukh 1981-12-25 00:00:00
2 Shradha Verma 1981-05-11 00:00:00
3 Divya Dutta 1982-07-21 00:00:00
4 Matthew Palmer 1983-12-28 00:00:00
table d:-
id fn ln dob
1 Shradha Tiwari 1981-12-25 00:00:00
2 Divya Dutta 1983-07-21 00:00:00
3 Sulabh Manesar 1975-09-11 00:00:00
4 Matthew Palmer 1983-12-28 00:00:00
5 Samuel Maxwell 1984-05-22 00:00:00
Now my original table is having about 17 columns and this is just a simpler version of it. The tables 'A' and 'D' are generated by a query. Table 'A' will be populated and Table D will be like a temporary table that gets its values from the query, compares all the First Names of each table and if it encounters any change , it needs to update the log table By the first name and also mentions all the columns that are different.
For this I have created a temporary table, viz. '#TMP_COMPARE' which takes all the columns of table 'a'. and then compares those columns against that of table 'd' and it has the columns PLN, PDOB, Pmatch which have values 0 by default and are set to one in case all columns match for that row(Pmatch=1), Last name matches (PLN=1), Dob matches (Pdob=1).
Once this '#TMP_COMPARE' compares the two tables I will then update the log table with the columns that dont match for a first name.
USE Testing
GO
IF OBJECT_ID('TEMPDB..#TMP_COMPARE') is not null
BEGIN
DROP TABLE #TMP_COMPARE
END
CREATE TABLE #TMP_COMPARE(
FN varchar(20),
LN varchar(20),
dob smalldatetime,
PLN int default 0,
Pdob int default 0,
Pmatch int default 0)
BEGIN
INSERT INTO #TMP_COMPARE
SELECT a.fn, a.ln, a.dob,
case when a.ln = d.Last_name AND a.dob = d.Birthdate
THEN 1
END AS #TMP_COMPARE.PMATCH,
CASE WHEN a.dob <> d.Birthdate
THEN 0
WHEN a.dob = d.Birthdate then 1
END AS #TMP_COMPARE.Pdob,
CASE WHEN a.ln <> d.Last_name
THEN 0
WHEN a.ln = d.Last_name
then 1
END AS #TMP_COMPARE.PLN
FROM dbo.a2 as a
JoIN d ON a.fn = d.First_Name
END
SELECT * FROM #TMP_COMPARE
Error I am getting is :-
Msg 102, Level 15, State 1, Line 24
Incorrect syntax near '.'
What is wrong in my query, and should I do this any other way please advice.
Now this is something very basic that is wrong in my query but I am a newbie and any help is very much appreciated.
Thanks in advance,
DCS
#log is a single scalar variable value and can only hold a single value at a given time. So you are unable to reference previous values of that variable, just what is currently there.
That means it's only going to display the last value (match) for every record in your select statement.
You may want to move the select inside the loop and change it to an insert into a logging table of some sort. That way you can just select * from loggingtable after the loop is over to retrieve all the data.
There is likely a way better way to handle this also, but I wanted to give a quick response (no time to refactor right now).
You can use a two character data field to store a result.
Position 1 = LN match state
Position 2 = Birthdate match state
11 = LN Match True ; Birthday Match True
10 = LN Match True ; Birthday Match False
01 = LN Match False; Birthday Match True
00 = LN Match False; Birthday Match True

How to merge 3 cells content in one in excel or by using sql

I have an excel csv file that i am uploading to sql server table using sqlbulkcopy,data in excel looks like this
121 **ABCDEFG** 138.00 141 XYZ
**HIJKLMN**
**OPQRSTUV**
So basically this 3 line make a single record in table,how should i merge these 3 line comments in one ?
I would probably do this line by line in VBA:
I'd initialize a few variables like startRow, currentRow, and lastRow
I'd create a recursive function that accepted a row number, and it would check if the NEXT rows first column was blank... if blank, it would return the current rows second column, plus the output of the same function using the next row number. if not blank, it would return the current rows second column. It would also check to see if the lastRow count had been hit.
The main loop would start at start row, and build a simple insert query, using the recursive function to get the note text for the second column, and then increment the currentRow counter. It would check the row to see if the first column was empty, and if so just continue to the next row. It would check to see if last row count has been reached.
change your query to something like this:
set nocount on;
declare #t table (Ro_No nvarchar(5), Comments nvarchar(20), Amount decimal(5,2))
insert into #t (Ro_No, Comments, Amount)
select '121','**ABCDEFG**' , 1.38 union
select '121','**HIJKLMN**' , 1.38 union
select '121','**OPQRSTUV**', 1.38 union
select '221','aaa' , 2.2 union
select '221','bbb' , 2.2 union
select '321','test3a' , 3.2 union
select '321','test3b' , 3.2
set nocount off
SELECT p1.Ro_No
,stuff(
(SELECT
', ' + p2.Comments
FROM #t p2
WHERE p2.Ro_No=p1.Ro_No
ORDER BY p2.Ro_No,p2.Comments
FOR XML PATH('')
)
,1,2, ''
) AS All_Comments
,p1.Amount
FROM #t p1
GROUP BY
Ro_No, Amount
OUTPUT:
Ro_No All_Comments Amount
----- ----------------------------------------- ------
121 **ABCDEFG**, **HIJKLMN**, **OPQRSTUV** 1.38
221 aaa, bbb 2.20
321 test3a, test3b 3.20
(3 row(s) affected)