SQL Can Return One or a Few Records
February 23, 2005 Hey Ted
SQL’s SELECT INTO statement works fine as long as only one record matches the criteria in the WHERE clause. If the query returns more than one record, the host variables are loaded with data, but the SQL State variable, SQLSTT, has a value of 21000, which according to the manual indicates a “Cardinality Violation.” Can I assume that the record loaded into the host variables really is the first record in the returned dataset? Or do you have a better suggestion?
I suspect that the data in the host variables comes from the record you’re looking for, but being the ultra-conservative I am (compared to me, Ronald Reagan is in the same league with Karl Marx), I wouldn’t count on it. Let me give you another suggestion.
If you’re at V5R1 or above, add the FETCH FIRST n ROWS ONLY clause to the SELECT statement. The number n can be omitted and defaults to the value one, and either ROW and ROWS is acceptable. Here’s an example:
select * into :SomeDataStructure from SomeTable Where Something = SomethingElse order by SomeField fetch first row only
If you’re running an earlier release, you’ll have to go to the trouble of declaring a cursor, opening it, and fetching from it one time.
You can use the FETCH FIRST n ROWS ONLY clause with the regular SELECT statement, not just SELECT INTO. I threw together the following short program to illustrate this usage. It lists the first five customers in alphabetical order by name. That is to say, it sorts the records in alphabetical order, then returns the first five records from the sorted data.
Fqsysprt o f 132 printer D SqlNormal c const('00000') D SqlEOF c const('02000') D Error s 12a D CustRec e ds extname(QCUSTCDT) C/exec sql C+ set option closqlcsr=*endmod C/end-exec C/exec sql C+ declare input cursor for C+ select * from qcustcdt C+ order by lstnam,init C+ fetch first 5 rows only C/end-exec C eval *inlr = *on C/exec sql C+ open input C/end-exec C if SqlStt <> SqlNormal C eval Error = 'Open' C return C endif C dow '1' C/exec sql C+ fetch input into :CustRec C/end-exec C if SqlStt = SqlEOF C leave C endif C if SqlStt <> SqlNormal C eval Error = 'Fetch' C except ErrorLine C return C endif C except DtlLine C enddo Oqsysprt e ErrorLine 1 O Error O SqlStt +0001 Oqsysprt e DtlLine 1 O CusNum O LstNam +0001 O Init +0001
I sometimes use FETCH FIRST n ROWS only in interactive SQL to create a small result set. It’s similar to using the Number of Records to Copy (NBRRCDS) parameter of the Copy File (CPYF) command.
I have read that some database management systems permit you to use a host variable to specify the number of rows to return. DB2/400 does not support this feature, at least not in V5R2. I tried it to make sure. I understand all databases in the DB2 family require you to hardcode a literal number of records.
Click here to contact Ted Holt by e-mail.