473,554 Members | 3,024 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Cursor Based SQL?

Does anyone have any good references they could recommend on Cursor
based SQL writing? I have to create SQL that can loop though records
simular to VB loops and I have been told that this is the way to go.
Any recommendations would be helpful.
Jul 20 '05 #1
7 2216
Philip Mette wrote:
Does anyone have any good references they could recommend on Cursor
based SQL writing? I have to create SQL that can loop though records
simular to VB loops and I have been told that this is the way to go.
Any recommendations would be helpful.

Don't listen to Java/C#/VB/<insert proc language of your choice> developers.
cursors and SQL are mutually exclusive.
A cursor is a way to interface SQL to procedural languages.

Cheers
Serge
Jul 20 '05 #2

"Philip Mette" <ph******@msn.c om> wrote in message
news:96******** *************** **@posting.goog le.com...
Does anyone have any good references they could recommend on Cursor
based SQL writing? I have to create SQL that can loop though records
simular to VB loops and I have been told that this is the way to go.
Any recommendations would be helpful.


You should never use a cursor unless there is no other possible solution -
TSQL is a set-based language, and MSSQL is heavily optimized to run
set-based code. Cursors are extremely slow, and they are not often
required - if you can give more details of what you're trying to do, someone
may be able to suggest a set-based approach.

If you do post more information, please include CREATE TABLE statements,
INSERTs for sample data, and sample output to make it easier to understand
what you're doing.

Simon
Jul 20 '05 #3
On 25 Aug 2004 07:26:50 -0700, Philip Mette wrote:
Does anyone have any good references they could recommend on Cursor
based SQL writing? I have to create SQL that can loop though records
simular to VB loops and I have been told that this is the way to go.
Any recommendations would be helpful.


Hi Philip,

Why do you think that you have to create SQL that can loop through rows
(not records!!)? About 95% of the times that someone thinks that looping
is the only way to solve a problem, it isn't. And a set-based solution is
faster than a cursor in 99.9% of these situations.

Why don't you post some more info about the problem you're trying to solve
instead of focussing on a (probably sub-optimal) choice of how to solve
it. Chances are that someone will help you find a set-based solution to
your problem.

The best way to post a problem is by supplying the table structure (as
copy-and-pasteable CREATE TABLE statements, including constraints), sample
data (as copy-and-pastteable INSERT statements) and expected output along
with a description of the business problem you're trying to solve and (if
you have it) your current SQL. http://www.aspfaq.com/etiquette.asp?id=5006
and http://vyaskn.tripod.com/code.htm#inserts provide some help on putting
together the information for a good posting.

Best, Hugo
--

(Remove _NO_ and _SPAM_ to get my e-mail address)
Jul 20 '05 #4
Philip Mette (ph******@msn.c om) writes:
Does anyone have any good references they could recommend on Cursor
based SQL writing? I have to create SQL that can loop though records
simular to VB loops and I have been told that this is the way to go.
Any recommendations would be helpful.


Here is a quick example which says everything you need to know:

create procedure TSQL_ProductPro c (@product int output)
as
begin
declare @sales int
declare c INSENSITIVE cursor for select intcolumn from tbl
open c

set @product = NULL

while 1 = 1
begin
fetch next from c into @sales
IF @@fetch_status <> 0
BREAK
set @product = coalesce(@produ ct, 1) * @sales
end

close c
deallocate c
end

Notes:

1) Always make cursors INENSITIVE. The default keyset cursor is
incomprehensibl e, to me at least, and has given me more than one bad
negative performance surprise. (Might have happened more in SQL 6.5.)

2) By putting the FETCH statement first in the loop, the code does not
only get shorter, it is also easier to maintain. If you have two
FETCH statements, and one is at the end of a long loop, you can
easily forget to augment that statement if you add another column
to the cursor, giving difficult-to-find errors, since the cursors
works on the first iteration in the loop.

Incidently, this example is a case a cursor might be necessary, as
there is no way to do this sort of thing in a set-based statment.
(You can use SUM with LOG and EXP for a product, if you only have
positive values, but not in the general case.)

As others have pointed out, cursors should only be used as a last
resort. First try to find a set-based way of attacking the problem.
For a large data set, the difference in performance may several
magnitudes.

But using cursors can sometimes cut development time considerably.
Say that you have a stored procedure that performs the task you
want to do on a set of scalar values received as parameters. Writing
a cursor loop which calls that procedure is a simple task. Rewriting
the stored procedure to handle an input set, may be a major undertaking.
And if you know that you the data set you will loop over will be modest
in size, it may simply not be worth the cost.
--
Erland Sommarskog, SQL Server MVP, es****@sommarsk og.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techinf...2000/books.asp
Jul 20 '05 #5
Erland Sommarskog <es****@sommars kog.se> wrote in message news:<Xn******* *************** @127.0.0.1>...
Philip Mette (ph******@msn.c om) writes:
Does anyone have any good references they could recommend on Cursor
based SQL writing? I have to create SQL that can loop though records
simular to VB loops and I have been told that this is the way to go.
Any recommendations would be helpful.


Here is a quick example which says everything you need to know:

create procedure TSQL_ProductPro c (@product int output)
as
begin
declare @sales int
declare c INSENSITIVE cursor for select intcolumn from tbl
open c

set @product = NULL

while 1 = 1
begin
fetch next from c into @sales
IF @@fetch_status <> 0
BREAK
set @product = coalesce(@produ ct, 1) * @sales
end

close c
deallocate c
end

Notes:

1) Always make cursors INENSITIVE. The default keyset cursor is
incomprehensibl e, to me at least, and has given me more than one bad
negative performance surprise. (Might have happened more in SQL 6.5.)

2) By putting the FETCH statement first in the loop, the code does not
only get shorter, it is also easier to maintain. If you have two
FETCH statements, and one is at the end of a long loop, you can
easily forget to augment that statement if you add another column
to the cursor, giving difficult-to-find errors, since the cursors
works on the first iteration in the loop.

Incidently, this example is a case a cursor might be necessary, as
there is no way to do this sort of thing in a set-based statment.
(You can use SUM with LOG and EXP for a product, if you only have
positive values, but not in the general case.)

As others have pointed out, cursors should only be used as a last
resort. First try to find a set-based way of attacking the problem.
For a large data set, the difference in performance may several
magnitudes.

But using cursors can sometimes cut development time considerably.
Say that you have a stored procedure that performs the task you
want to do on a set of scalar values received as parameters. Writing
a cursor loop which calls that procedure is a simple task. Rewriting
the stored procedure to handle an input set, may be a major undertaking.
And if you know that you the data set you will loop over will be modest
in size, it may simply not be worth the cost.


---Ok I will send you the table and fields names along with the psuedo
logic of what i need done to get you started since you ask.:) I will
send the create table and data statements soon. Here is what I need.

A collector takes or makes calls. During this call he gets a PTP or
promise to pay. This activity is stored in tblDailyActivit ies and the
activity status is 'OP' or Open by default. In another table,
tblDailyPayment s store payments that have come in through out the
month.
Here are the tables:
tblDailyActivit ies
Record_Key_Num
Acct_Num
Activity_Date (Date Promise to Pay Was Made)
Promise_Amt_1
Due_Date (Date Next Payment Is Due)
Promise_Status
Total_Dollars_C oll

tblDailyPayment s
Record_Key_Num
Acct_Num
Pay_Amt
Activity_Date (Date Payment Was Made)
Here is the logic.(Keep in mind that their can be more than one
promise made on same acct by the same or different collector so the
logic is handling this, you will see.)

For Each [Acct_Num and Due_Date] combination
Look for payments from the tblDailyPayment s Table with an
activity_date that are within tblDailyActivit es.Activity_Dat e + 10
days.
If the sum of Payments>=90% of
tblDailyActivit ies.Promise_Amt _1 then
Update tblDailyActivit ies.Promise_Sta tus =
'PK' and tblDailyActivit es.Total_Dollar s_Coll= 'Sum (of Payments)'
And all other same [Acct_Num and Due_Date]
combination's update tblDailyActivit ies.Promise_Sta tus = 'IP'
Else If the sum of Payments<90% of
tblDailyActivit ies.Promise_Amt _1, then
If tblDailyActivit es.Activity_Dat e +10 days > today's date, then
tblDailyActivit ies.Promise_Sta tus= 'OP' and exit loop
Else If tblCacsDailyAct ivites.Activity _Date +10 days < today's
date, then
Update tblCacsDailyAct ivities.Promise _Status = 'PB'
And move to record 2 of same [Acct_Num and Due_Date] combination.

And repeat until end of loop.

HERES SOME DATA SAMPLE:

TBLDAILYACTIVIT IES
RecKey Account ActivityDate DueDate UserId PromiseAMt PromiseDate
PromiseStatus TotalColl
688849 7339344 08/06/2004 08/30/2004 MPJ5 525.00 08/16/2004
OP <Null>
688850 7339344 08/07/2004 08/30/2004 MPJ5 525.00 09/15/2004
OP <Null>

688851 7339344 08/20/2004 09/30/2004 MPLI 600.00 09/15/2004
OP <Null>
688852 7339344 08/21/2004 09/30/2004 MPLT 700.00 10/15/2004
OP <Null>

688853 6116655 08/12/2004 08/30/2004 MP60 500.00 09/15/2004
OP <Null>
688854 6116655 08/12/2004 08/30/2004 MP61 550.00 09/15/2004
OP <Null>

TBLDAILY PAYMENTS
RecKey Account PayAmt ActivityDate
1254 7339344 225.00 08/10/2004
1255 7339344 295.00 08/11/2004
1259 7339344 300.00 08/20/2004
1354 6116655 250.00 08/13/2004

OUTPUT
RecKey Account ActivityDate DueDate UserId PromiseAMt PromiseDate
PromiseStatus TotalColl
688849 7339344 08/06/2004 08/30/2004 MPJ5 525.00 08/16/2004
PK 520.00
688850 7339344 08/06/2004 08/30/2004 MPJ5 525.00 09/15/2004
IP <Null>

688851 7339344 08/20/2004 09/30/2004 MPLI 525.00 09/15/2004
OP 300.00
688852 7339344 08/21/2004 09/30/2004 MPLT 525.00 10/15/2004
IP <Null>

688853 6116655 08/12/2004 08/30/2004 MP60 500.00 09/15/2004
PB 250.00
688854 6116655 08/12/2004 08/30/2004 MP61 550.00 09/15/2004
IP <Null>
THE FIRST TABLE REPRESENTS ACTIVITIES THE SECOUND PAYMENTS THAT COME
IN.
THE 3RD IS HOW THE DATA SHOULD LOOK. THIS IS BASED OFF OF ACCT AND
DUEDATE COMBINATIONS SO THE LOOP
WILL STARTS OVER ON THE SAME ACCT IF THE DUEDATE CHANGES. SINCE THE
2ND GROUP OF RECORDS STILL
IS IN THE 10 DAY WINDOW FROM ACTIVITY DATE TO TODAY WE KEEP IT OPEN
EVEN THOUGH THE AMOUNT IS LESS THAN 90%.
BECAUSE THEY HAVE A FEW MORE DAYS TO GET MORE PAYMENTS IN TO MAKE THIS
A PK. THE GOAL IS TO GET THE FIRST RECORD OF A
ACCT DUEDATE GROUP MARK IT EITHER PK OR PB AND MOVE TO THE NEXT UNTILL
YOU FIND A PK ONCE A PK IS FOUND MARK ALL OTHERS WITH
IN THAT GROUP IP. TOTAL DOLLARS IS ONLY RECORDED IN PK OP AND PB.









If this can be done without cursors I will be very thankful. You all
out on the posting boards have been great. Thanks so much for all your
assistance. You make SQL coding exciting.
Jul 20 '05 #6
Erland Sommarskog <es****@sommars kog.se> wrote in message news:<Xn******* *************** @127.0.0.1>...
Philip Mette (ph******@msn.c om) writes:
Does anyone have any good references they could recommend on Cursor
based SQL writing? I have to create SQL that can loop though records
simular to VB loops and I have been told that this is the way to go.
Any recommendations would be helpful.


Here is a quick example which says everything you need to know:

create procedure TSQL_ProductPro c (@product int output)
as
begin
declare @sales int
declare c INSENSITIVE cursor for select intcolumn from tbl
open c

set @product = NULL

while 1 = 1
begin
fetch next from c into @sales
IF @@fetch_status <> 0
BREAK
set @product = coalesce(@produ ct, 1) * @sales
end

close c
deallocate c
end

Notes:

1) Always make cursors INENSITIVE. The default keyset cursor is
incomprehensibl e, to me at least, and has given me more than one bad
negative performance surprise. (Might have happened more in SQL 6.5.)

2) By putting the FETCH statement first in the loop, the code does not
only get shorter, it is also easier to maintain. If you have two
FETCH statements, and one is at the end of a long loop, you can
easily forget to augment that statement if you add another column
to the cursor, giving difficult-to-find errors, since the cursors
works on the first iteration in the loop.

Incidently, this example is a case a cursor might be necessary, as
there is no way to do this sort of thing in a set-based statment.
(You can use SUM with LOG and EXP for a product, if you only have
positive values, but not in the general case.)

As others have pointed out, cursors should only be used as a last
resort. First try to find a set-based way of attacking the problem.
For a large data set, the difference in performance may several
magnitudes.

But using cursors can sometimes cut development time considerably.
Say that you have a stored procedure that performs the task you
want to do on a set of scalar values received as parameters. Writing
a cursor loop which calls that procedure is a simple task. Rewriting
the stored procedure to handle an input set, may be a major undertaking.
And if you know that you the data set you will loop over will be modest
in size, it may simply not be worth the cost.


Ok I realize my last post was probably difficult to follow so mabye
someone can interpret this. I know how to write what I want in Oracle
SQL can someone convert it for me . I do not know MS SQL enough to
make the change.
Here is the code:

CREATE OR REPLACE PROCEDURE UPD_ACTIVITY IS
CURSOR ACT_cur1
IS
SELECT DISTINCT A.ACCT_NUM, A.ACTIVITY_DATE
FROM TBLCACSDAILYACT IVITIES A ; /* this picks the unique
combination of acct and date*/

tot_pay number ;
rec_upd varchar2(1);
todays_date date;
BEGIN
dbms_output.put _line('inside upd_activity ');
SELECT SYSDATE INTO todays_date FROM DUAL;
FOR ACT_CUR_REC1 IN ACT_CUR1
LOOP
rec_upd := 'N';
DECLARE
CURSOR ACT_CUR2 IS
SELECT B.ACCT_NUM,
B.ACTIVITY_DATE ,B.PROMISE_AMT_ 1,B.PROMISE_STA TUS,
B.TOTAL_DOLLARS _COLL
FROM TBLCACSDAILYACT IVITIES B
WHERE B.ACCT_NUM = ACT_CUR_REC1.AC CT_NUM
AND B.ACTIVITY_DATE = ACT_CUR_REC1.AC TIVITY_DATE
ORDER BY B.ACTIVITY_DATE
FOR UPDATE OF B.PROMISE_STATU S,B.TOTAL_DOLLA RS_COLL
NOWAIT;
BEGIN
dbms_output.put _line('inside upd_activity111 1 ');
FOR ACT_CUR_REC2 IN ACT_CUR2
LOOP
BEGIN
SELECT SUM(C.PAY_AMT) into tot_pay
FROM TBLCACSDAILYPAY MENTS C
WHERE C.ACCT_NUM = ACT_CUR_REC2.AC CT_NUM
AND C.ACTIVITY_DATE >= ACT_CUR_REC2.AC TIVITY_DATE
AND C.ACTIVITY_DATE < ACT_CUR_REC2.AC TIVITY_DATE+10;
dbms_output.put _line('tot_pay =');
IF tot_pay >= .9 * ACT_CUR_REC2.PR OMISE_AMT_1 THEN
IF rec_upd = 'N' THEN /* recs have not bee updated for promise
status*/
UPDATE TBLCACSDAILYACT IVITIES
SET PROMISE_STATUS = 'PK',
TOTAL_DOLLARS_C OLL = tot_pay
WHERE CURRENT OF ACT_CUR2;
rec_upd := 'Y';
ELSIF rec_upd = 'Y' THEN
UPDATE TBLCACSDAILYACT IVITIES
SET PROMISE_STATUS = 'IP'
WHERE CURRENT OF ACT_CUR2;
END IF;
ELSIF tot_pay < .9 * ACT_CUR_REC2.PR OMISE_AMT_1 THEN
IF (ACT_CUR_REC2.A CTIVITY_DATE+10 ) > todays_date THEN
UPDATE TBLCACSDAILYACT IVITIES
SET PROMISE_STATUS = 'OP'
WHERE CURRENT OF ACT_CUR2;
ELSE
UPDATE TBLCACSDAILYACT IVITIES
SET PROMISE_STATUS = 'PB'
WHERE CURRENT OF ACT_CUR2;
END IF;
END IF;
END;
END LOOP; /* end of ACT_CUR_REC2 loop */
END;
END LOOP; /*end of ACT_CUR_REC1 */
END ; /* end of proc */
/
Thanks again!
Jul 20 '05 #7
Philip Mette (ph******@msn.c om) writes:
---Ok I will send you the table and fields names along with the psuedo
logic of what i need done to get you started since you ask.:) I will
send the create table and data statements soon. Here is what I need.


Yes, this appears to be doable with set-based statements, an outline
follows. Had you included your tables and data with CREATE TABLE and
INSERT statements, I would have been able to test my solution.

I also need to insert the disclaimer that I don't think I understand
the business requirements completely. The algorithm indeeds looks funny
to me. What if for the first two rows there are payments for the first
promise? What if there are payments that match more than one combination?

And there is a contradiction between verbal description and the Oracle
code you posted. The narrative says account/duedate, but the Oracle
code does not touch duedate. ActivityDate appears to better macthc results.

-- First we need some extra columns to play with, so we move to a temp
-- table. Here create with SELECT INTO to save some typing.
SELECT *, isfirst = convert(bit, 0) INTO #t FROM TBLCACSDAILYACT IVITIES

-- Set is first bit.
UPDATE #t
SET isfirst = 1
FROM #t
JOIN (SELECT RecKey = MIN(RecKey)
FROM #t
GROUP BY Account, ActivityDate) AS c
ON #t.RecKey = c.RecKey

-- Set totals.
UPDATE #t
SET TotalColl = p.payamt
FROM #t t
JOIN (SELECT t.Account, t.ActivityDate, payamt = SUM(t.Payment)
FROM #t
JOIN dailypayments d
ON t.account = p.account
AND p.ActivityDate BETWEEN t.ActivityDate AND t.ActivityDate + 10
GROUP BY t.account, t.ActivtithDate ) AS s
ON t.Account = s.Account
AND t.AcctivityDate = s.ActivityDate

-- Now clear total where we should save, and set status
UPDATE #t
SET TotalCol1 = CASE WHEN TotalCol1 > 0.9 * PromsieAmt AND isfirst = 1
THEN TotalCol1
ELSE NULL
END,
Status = CASE WHEN TotalCol1 > 0.9 * PromsieAmt
THEN CASE isfirst WHEN 1 THEN 'PK' ELSE 'IP' END
ELSE CASE WHEN dateadd(DAY, ActivityDate, 10) >
convert(char(8) , getdate(), 112)
THEN 'OP'
ELSE 'PB'
END
END

-- Final update of table left as exercise for the reader.

--
Erland Sommarskog, SQL Server MVP, es****@sommarsk og.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techinf...2000/books.asp
Jul 20 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
11251
by: sci | last post by:
Could someone help me by answering the questions below? What's a cursor? What's difference between Query and View? Is a RecordSet just part of a table? Can it be part of a query of view? If the content in a table changed, is it necessary for a old recordset to renew itself by do "Requery()"? Thanks for your help!
15
3804
by: Philip Mette | last post by:
I am begginner at best so I hope someone that is better can help. I have a stored procedure that updates a view that I wrote using 2 cursors.(Kind of a Inner Loop) I wrote it this way Because I couldn't do it using reqular transact SQL. The problem is that this procedure is taking longer and longer to run. Up to 5 hours now! It is...
1
6417
by: jfro | last post by:
After trying every way I could come up with I can't get a filter clause to work with a passed variable ... I have a cursor that pulls a filter string from a table (works OK), then I want to use that filter in a second cursor, but can't get the syntax ... @bakfilter is equal to "MISV2_db_%.BAK" before I try to open and fetch from the second...
10
1685
by: Neil | last post by:
I need to get two values from a complex SQL statement which returns a single record and use those two values to update a single record in a table. In order to assign those two values to variables and then use those variables in the UPDATE statement, I created a cursor and used Fetch Next.... Into. This way, I only have to call the complex SQL...
3
4892
by: PeP | last post by:
Good morning, I have a form containing a text-area, I'd like to know if it exists a function that, when I activate an event, returns the position of the cursor in the text-area. For example, I write ten words in the text-area, then I move the cursor at the beginning of the second word and activate the event (for example, click on a...
1
7393
by: klalonde | last post by:
I was researching opinions on using cursors in stored procedures and found a thread http://www.thescripts.com/forum/thread143091.html discussing (generally) why not to use them. I took a cursor-based solution and took a stab at writing the equivalent to it as a set-based procedure. I then timed each process using Query Profiler by executing...
2
3376
by: satishchandra999 | last post by:
I have SP, which has a cursor iterations. Need to call another SP for every loop iteration of the cursor. The pseudo code is as follows.. Create proc1 as Begin Variable declrations... declare EffectiveDate_Cursor cursor for select field1,fld2 from tab1,tab2 where tab1.effectivedate<Getdate()
0
2293
by: rkandas | last post by:
Order by based on input Select col1, col2, col3 from table 1 order by col1 <ASC/DESC>, col2 <ASC/DESC>, col3 <ASC/DESC> The sort order for col1, col2, col3 are parameters to the program. Can anyone explain how to parametrize the sort order without using a dynamic sql. DECLARE cursor clause based on parameter DECLARE CURSOR csr1...
36
2345
by: CK | last post by:
How do I write a set based query? I have a groupSets table with fields setId, idField, datasource, nameField, prefix, active Data: 1,someIDfield, someTable, someField, pre1, 1 2,someotherIDfield, someTable, someotherField, pre2, 1 3,somethirdIDfield, someTable, somethirdField, pre3, 1 4,somefourthIDfield, someotherTable, somefourthField,...
1
7547
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
7879
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
6129
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5426
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
3548
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
3536
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
2009
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1117
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
828
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.