Procedure with cursor has missing output - sql

I am working on an SQL Server procedure that I would like to have print the department name and students name Similar to the attached snippet
The formatting should look like the attached sample snippet and there are two columns involved. students and department tables.
The problem is that the results are incomplete/seems to be getting cut off
below is the code that I am using
use testDB
go
CREATE PROCEDURE pro_depart11
AS
SET NOCOUNT ON;
declare #depcount as int;
declare #val as int;
declare #studentN as NVARCHAR(500);
declare #dname varchar(500);
set #val = 1;
set #depcount = (select count(*) from DEPARTMENT);
PRINT '************procedure pro_department report************'
While (#val<=#depcount)
begin
set #dname = (select DNAME from DEPARTMENT where DEPTid=#val)
PRINT '******************'+ #dname + '*************************'
declare getnam_cursor cursor for
SELECT sname FROM STUDENT s inner join DEPARTMENT d on s.DEPT_ID = d.DEPTID WHERE d.DEPTID = #val
group by sname order by sname asc;
open getn_cursor
FETCH NEXT FROM getnam_cursor into #studentN
WHILE ##FETCH_STATUS = 0
BEGIN
Print CAST(#studentN as varchar (500))
set #val = #val + 1;
FETCH NEXT FROM getnam_cursor into #studentN
end
close getnam_cursor;
deallocate getnam_cursor;
end
To run the script exec pro_depart11;
I've also included a snippet of the tables. students then department tables
The third snippet is of the results I am getting. I am not sure where I am going wrong with the code or how to best fix it, any help is greatly appreciated.
Below is the DLL/DML codes involved for the table/inserts
CREATE TABLE dbo.STUDENT
(snum int,
sname nvarchar(12),
MAJOR nvarchar(12),
DEPT_ID int,
slevel nvarchar(12),
AGE int,
CONSTRAINT STUDENT_SNUM_pk PRIMARY KEY (SNUM));
CREATE TABLE dbo.DEPARTMENT
(DEPTid int,
DNAME nvarchar(100),
LOCATION nvarchar(100),
insert into dbo.STUDENT values (0418,'S.Jack','Math',2,'SO',17);
insert into dbo.STUDENT values (0671,'A.Smith','English',2,'FR',20);
insert into dbo.STUDENT values (1234,'T.Banks','ME',3,'SR',19);
insert into dbo.STUDENT values (3726,'M.Lee','Physics',4,'SO',21);
insert into dbo.STUDENT values (4829,'J.Bale','Chemistry',5,'JR',22);
insert into dbo.STUDENT values (5765,'L.Lim','CS',1,'SR',19);
insert into dbo.STUDENT values (0019,'D.Sharon','History', 4,'FR',20);
insert into dbo.STUDENT values (7357,'G.Johnson','Math', 4,'JR',19);
insert into dbo.STUDENT values (8016,'E.Cho','History',2,'JR',19);
insert into dbo.DEPARTMENT values (1,'Computer Sciences','West Lafayette');
insert into dbo.DEPARTMENT values (2,'Management','West Lafayette');
insert into dbo.DEPARTMENT values (3,'Medical Education','Purdue Calumet');
insert into dbo.DEPARTMENT values (4,'Education','Purdue North Central');
insert into dbo.DEPARTMENT values (5,'Pharmacal Sciences','Indianapolis');

First key point, you don't need a nested loop, order by department and have a condition for when the name changes.
declare #StudentName varchar(32), #DeptName varchar(32), #OldDeptName varchar(32) = '';
declare getnam_cursor cursor for
select s.sname StudentName, d.dname DeptName
from #Student s
inner join #Department d on d.deptid = S.Dept_id
order by d.dname, s.sname asc;
open getnam_cursor;
while 1 = 1 begin
fetch next from getnam_cursor into #StudentName, #DeptName;
if ##fetch_status != 0 break;
if #OldDeptName <> #DeptName begin
-- Ensure the line is the same length regardless of the length of the name
print(replicate('*',18) + ' ' + #DeptName + ' ' + replicate('*',32-len(#DeptName)));
set #OldDeptName = #DeptName;
end;
print(#StudentName);
end;
close getnam_cursor;
deallocate getnam_cursor;
Returns:
****************** Computer Sciences ***************
L.Lim
****************** Education ***********************
D.Sharon
G.Johnson
M.Lee
****************** Management **********************
A.Smith
E.Cho
S.Jack
****************** Medical Education ***************
T.Banks
****************** Pharmacal Sciences **************
J.Bale
Other points to note:
Use good layout and whitespace and you (and others will be able to follow your code easily).
Use consistent casing for your code and column names. Mixing it up just makes it hard to read.
Don't prefix column names when they are unique by table e.g. dname, sname - just use Name.
Always explicitly list the columns you are inserting into
Don't assume your department ids are sequential... in real life they might not be.
You don't need a group by unless you are aggregating (which you aren't).

Related

I'm trying this scenario but it is not giving correct output

//*
WAP which takes deptno,dname as input and
insert that records into dept table.
if deptno is already existing,then increment
its value by 10 and again try inserting.The
insert is suposed to be tried 5 times and
falling all 5 times, print amessage saying
'Try later'
*//
Alter procedure sp_update (
#dno int,
#dname varchar(30)
)
as begin
declare #rowcount int
set #rowcount=##ROWCOUNT
if #rowcount<5
begin
if not exists (select dno from dept where #dno=dno)
begin
insert into dept (dno,dname) values (#dno,#dname)
end
else
begin
print 'Try later'
end
end
else
begin
set #dno=(select max(dno) from dept)
set #dno=#dno+10
insert into dept (dno,dname) values (#dno,#dname)
end
end
exec sp_update 10,'HR'
Please give the required output.
The #rowcount variable at the begining of the procedure is always <5, it's never going to enter the segment where "increment its value by 10 and again try inserting".
EDIT: In order to know how many times a user has executed the SP, you would have to insert into a log table, something like:
CREATE TABLE logSp (Username VARCHAR(200), ProcedureName VARCHAR(200), DateExecuted DATETIME)
And change the logic to this:
ALTER PROCEDURE sp_update (
#dno int,
#dname varchar(30)
)
AS
BEGIN
DECLARE #sp_name VARCHAR(200) = 'sp_update'
DECLARE #maxtimes VARCHAR(200) = 5
DECLARE #user VARCHAR(200) = SUSER_NAME()
DECLARE #times INT
SELECT #times = count(1)
FROM logSp
WHERE Username = #user
AND ProcedureName = #sp_name
IF #times = #maxtimes
BEGIN
PRINT 'Try Again'
RETURN
END
ELSE
BEGIN
INSERT INTO logSp values (#user, #sp_name, GETDATE())
END
IF NOT EXISTS (SELECT dno FROM dept WHERE #dno=dno)
BEGIN
INSERT INTO dept (dno,dname) VALUES (#dno,#dname)
END
ELSE
BEGIN
SET #dno=(SELECT MAX(dno) FROM dept)
SET #dno=#dno+10
INSERT INTO dept (dno,dname) VALUES (#dno,#dname)
END
END
Also, by setting the #dno variable to max(id) + 10 you guarantee that
the new deptno doesn't exist, yout don't have to try 5 times. If you want to try 5 times the INSERT you would have to use a while.

SQL Query To Get Structured Result

Sir, below is my SQL query, followed with two images of Query Result & Required Output.
As you can see on Result image that I have got this output from executing the following query.
There is second image of Required Output. I would need to display the output in that format. As First Department name should be at top & below Project details correspond to that department. The same cycle should get repeated for each and every department.
How should I achieve this ?
SQL Code:
DECLARE #ColName varchar(20)=null,
#Query varchar(MAX)=null,
#DepartmentName varchar(50)=null,
#deptt_code varchar(4)=null,
#DistrictId varchar(4)='0001',
#Deptt_Id char(4)=null,
#stYear varchar(4)=null,
#cYear varchar(4)=null,
#yr varchar(9)='2017-2018',
#tno int
BEGIN
set #stYear = SUBSTRING(#yr,0,5);
set #cYear = SUBSTRING(#yr,6,4);
--CREATE DYNAMIC TABLE WITH COLs
DECLARE #DepartmentTable table
(
department_name varchar(50),
department_code varchar(4)
);
DECLARE #ProjectTable table
(
project_name varchar(130),
project_code varchar(15),
department_code varchar(4),
department_name varchar(50),
district_code varchar(4),
district_name varchar(30),
tehsil_code varchar(6),
tehsil_name varchar(30),
service_code varchar(3),
[service_name] varchar(30),
sector_code varchar(3),
sector_name varchar(30),
project_start_year varchar(8),
project_compl_year varchar(8),
financial_year varchar(9)
);
--Insert into Department Table
INSERT INTO #DepartmentTable (department_code, department_name)
select deptt_code,deptt_name+'('+ RTRIM(LTRIM(deptt_short))+')' as dept_name from m_Department
where deptt_code in (select distinct department_code from t_Project_Details where district_id=#DistrictId
and financial_year=#yr);
--Insert into Project Table With Corresponding Department Name & Code
insert into #ProjectTable (
department_code,
project_code,
project_name,
department_name,
district_code,
district_name,
tehsil_code,
tehsil_name,
service_code,
[service_name],
sector_code,
sector_name,
project_start_year,
project_compl_year,
financial_year
)
SELECT pd.department_code,
pd.project_Code,
pd.project_name,
d.deptt_name,
pd.district_id,
di.district_name,
pd.tehsil_id,
t.tehsil_name,
pd.service_code,
s.[service_name],
pd.sector_code,
se.sector_name,
CONVERT(varchar,YEAR(pd.project_initiation_fin_from_yr)) + ' ' + CONVERT(varchar(3),pd.project_initiation_fin_from_yr,100) as project_start_year,
CONVERT(varchar,YEAR(pd.project_initiation_fin_to_yr)) + ' ' + CONVERT(varchar(3),pd.project_initiation_fin_to_yr,100) as project_compl_year,
pd.financial_year
FROM t_Project_Details pd
INNER JOIN m_Department d
ON d.deptt_code=pd.department_code
INNER JOIN m_Service s
ON s.service_code = pd.service_code
INNER JOIN m_Sector se
ON se.sector_code=pd.sector_code
INNER JOIN m_District di
ON di.district_code=pd.district_id
INNER JOIN m_Tehsil t
ON t.tehsil_code = pd.tehsil_id
WHERE
district_id=#DistrictId and
financial_year=#yr;
--select all from Department Table;
select * from #ProjectTable;
END
Query Result Image: https://drive.google.com/open?id=0Bxn7UXgmstmRaS1qX21kbjlwZzg
Required Output Image: https://drive.google.com/open?id=0Bxn7UXgmstmRekJkUWhBcmNCbk0
Your required output is a presentation layer issue; SQL can return your results but cannot make one row contain one thing and following rows contain many different things in a different format.
A SQL resultset will contain the same number of columns in all rows each with the same datatype.
Use something like SSRS to acheive your desire output.

How do I print odd and even numbers on two seperate tables in SQL?

I've got this far in my SQL code. I am struggling to get my data to be printed in two separate table according to odd and even numbers. Thanks in advance for your input. I really appreciate it.
DECLARE
#empNM CHAR(15),
#empID INT,
#reportsTO INT
DECLARE
emp CURSOR dynamic FOR
SELECT Employee_NM, Employee_ID, ReportsTo
FROM employeetable
ORDER BY Employee_ID ASC
OPEN emp
FETCH NEXT
FROM emp
INTO #empNM, #empID, #reportsTO;
PRINT 'name id boss'
WHILE (##fetch_status <> -1)
IF (#empID % 2 = 0)
BEGIN
SET #empNM = CONVERT(CHAR,CAST(#empNM AS VARCHAR),1)
PRINT CAST(#empNM AS VARCHAR)+CAST(#empID AS VARCHAR)+SPACE(11)+CAST(#reportsTO AS varCHAR)
FETCH NEXT
FROM emp
INTO #empNM, #empID, #reportsTO;
END;
ELSE
BEGIN
SET #empNM = CONVERT(CHAR,CAST(#empNM AS VARCHAR),1)
PRINT CAST(#empNM AS VARCHAR)+CAST(#empID AS VARCHAR)+SPACE(11)+CAST(#reportsTO AS varCHAR)
FETCH NEXT
FROM emp
INTO #empNM, #empID, #reportsTO;
END;
CLOSE emp;
DEALLOCATE emp;
This is the desired outcome...
You are not using C# looping through data. With SQL, you must work on the whole set of data, hence no cursor. (in most cases)
You must execute 1 insert for each table:
Insert Into TOdd(Name, Id, Boss) Select Name, Id, Boss From T Where id % 2 = 1
Insert Into TEven(Name, Id, Boss) Select Name, Id, Boss From T Where id % 2 = 0
See SQL Fiddle: http://sqlfiddle.com/#!3/212a9/1/0

T-SQL Stored Procedure with While Loop causing Errors in Primary Key Constraints

So I have this MS SQL Stored Procedure:
ALTER PROCEDURE [dbo].[Import_Agent_Client_Bucket_2010]
AS
BEGIN
-- Loop Through Each Agent, Create a Bucket, Add their Clients to the Bucket
DECLARE Agent_Cursor CURSOR FOR
SELECT Agent_GUID, Agent_ID
FROM realforms_2011.dbo.Agent
DECLARE #Agent_GUID uniqueidentifier
DECLARE #Agent_ID int
OPEN Agent_Cursor;
FETCH NEXT FROM Agent_Cursor
INTO #Agent_GUID, #Agent_ID;
WHILE ##FETCH_STATUS = 0
BEGIN
-- Create a bucket for each agent
DECLARE #cbPKTable TABLE (cbPK UNIQUEIDENTIFIER, cbID int)
INSERT INTO realforms_2011.dbo.Client_Bucket ([Description] ) OUTPUT inserted.Client_Bucket_GUID, inserted.Client_Bucket_ID INTO #cbPKTable
SELECT ISNULL(a.First_Name, ' ') + ' ' + ISNULL(a.Last_Name, ' ') + '''s Clients'
FROM realforms_2011.dbo.Agent a
WHERE Agent_GUID = #Agent_GUID
DECLARE #Client_Bucket_GUID uniqueidentifier
SELECT #Client_Bucket_GUID = cbPK FROM #cbPKTable
DECLARE #Client_Bucket_ID int
SELECT #Client_Bucket_ID = cbID FROM #cbPKTable
INSERT INTO realforms_2011.dbo.Agent_Client_Bucket (Agent_GUID, Agent_ID, Client_Bucket_GUID, Client_Bucket_ID)
VALUES (#Agent_GUID, #Agent_ID, #Client_Bucket_GUID, #Client_Bucket_ID)
DECLARE #Client_GUID uniqueidentifier
DECLARE #Client_ID int
-- Get clients from the server (2010)
DECLARE Client_Cursor CURSOR FOR
SELECT C.Client_ID
FROM realforms.dbo.Client C
INNER JOIN realforms.dbo.Agent_Client AC ON AC.Client_ID = C.Client_ID
WHERE AC.Agent_ID = #Agent_ID
ORDER BY C.Client_ID ASC
OPEN Client_Cursor;
FETCH NEXT FROM Client_Cursor
INTO #Client_ID
-- loop through each 2010 client
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #myNewPKTable TABLE (myNewPK UNIQUEIDENTIFIER)
INSERT INTO realforms_2011.dbo.Client (Client_ID,Name,Secondary_Name,[Address],Address_2,City_State_Zip,Phone,Email_Address,Secondary_Email_Address,Create_Date,Last_Change_Date,[Status],File_Under,[Year]) OUTPUT inserted.Client_GUID INTO #myNewPKTable
SELECT c.Client_ID,Name,Secondary_Name,[Address],Address_2,City_State_Zip,Phone,Email_Address,Secondary_Email_Address,Create_Date,Last_Change_Date,[Status],File_Under,2010
FROM realforms.dbo.Client C
INNER JOIN realforms.dbo.Agent_Client AC ON AC.Client_ID = C.Client_ID
WHERE AC.Agent_ID = #Agent_ID AND C.Client_ID = #Client_ID
SELECT #Client_GUID = myNewPK FROM #myNewPKTable
INSERT INTO realforms_2011.dbo.Client_Bucket_Client (Client_Bucket_GUID, Client_GUID, Client_ID, Client_Bucket_ID, [Year])
VALUES (#Client_Bucket_GUID, #Client_GUID, #Client_ID, #Client_Bucket_ID, 2010)
PRINT 'Client Bucket GUID: '
PRINT #Client_Bucket_GUID
PRINT 'Client GUID: '
PRINT #Client_GUID
FETCH NEXT FROM Client_Cursor
INTO #Client_ID;
END;
CLOSE Client_Cursor;
DEALLOCATE Client_Cursor;
FETCH NEXT FROM Agent_Cursor
INTO #Agent_GUID, #Agent_ID;
END;
CLOSE Agent_Cursor;
DEALLOCATE Agent_Cursor;
END
But I get an error message on just a very few of the items, it says
Msg 2627, Level 14, State 1, Procedure
Import_Agent_Client_Bucket_2010, Line
71 Violation of PRIMARY KEY constraint
'Client_Bucket_Client_PK'. Cannot
insert duplicate key in object
'dbo.Client_Bucket_Client'. The
statement has been terminated.
EDIT:
OK, I see what you're doing there, I apologize for missing the OUTPUT statement. Based on that information, it seems like the code could break if a record is not inserted into the Client table in the line right before SELECT #Client_GUID = myNewPK FROM #myNewPKTable. If no record is inserted, you would wind up grabbing the GUID from the previous record and when you go to insert that it would cause the PK violation. You might have to check to make sure that records are being inserted into the Client table.
ORIGINAL ANSWER:
It looks like you're declaring a table:
DECLARE #myNewPKTable TABLE (myNewPK UNIQUEIDENTIFIER)
But then you never put anything into it, so this statement must return null:
SELECT #Client_GUID = myNewPK FROM #myNewPKTable
EDIT:
Why not just do this? I don't see why the table #myNewPKTable is even being created.
SET #Client_GUID = NEWID()
EDIT:
I think the reason you are getting the primary key violation is because #Client_Bucket_GUID is null. At the beginning of the procedure, there is this code:
-- Create a bucket for each agent
DECLARE #cbPKTable TABLE (cbPK UNIQUEIDENTIFIER, cbID int)
...
DECLARE #Client_Bucket_GUID uniqueidentifier
SELECT #Client_Bucket_GUID = cbPK FROM #cbPKTable
After this code is run #Client_Bucket_GUID will always be null. Again, you would have to insert records into #cbPKTable if you wanted to get anything out of it. If you're trying to create a new UNIQUEIDENTIFIER and store it in #Client_Bucket_GUID, just use the NEWID() function.

Concatenating Columns from a Result Set in SQL Server 2000

I have a query that returns data in the following form
attribute value
--------- ----------
petid 1000
name buttercup
species cat
age 10
owner Bob Dole
Basically I want to go through every row and return the fields name and species in a single string, so here the result would be
buttercup cat
Any ideas how I could do this?
Try this. I've only tried it with SQL Serer 2008, but maybe it will work:
DECLARE #Concat nvarchar(50)
SET #Concat=N''
SELECT #Concat = #Concat + Value + N' '
FROM dbo.AttributeValue
WHERE Attribute IN (N'name', N'species')
SELECT #Concat
Okay - Now I think I understand the data format...
Here is the code to create the sample set (just to make sure I've got it right)
CREATE TABLE MyTable
(
attribute varchar(20),
value varchar(20)
)
INSERT INTO MyTable VALUES('petid','1000')
INSERT INTO MyTable VALUES('name','buttercup')
INSERT INTO MyTable VALUES('species','cat')
INSERT INTO MyTable VALUES('age','10')
INSERT INTO MyTable VALUES('owner','Bob Dole')
Here is my answer:
SELECT a.value + ' ' +b.value
FROM MyTable AS a
INNER JOIN MyTable AS b ON a.attribute='name' AND b.attribute = 'species'
The cursor way of doing this would be some thing like this-
DECLARE #name varchar(20)
DECLARE #species varchar(20)
DECLARE nameSpeciesCursor CURSOR FOR
SELECT name, species FROM tableName
OPEN nameSpeciesCursor
FETCH NEXT FROM nameSpeciesCursor INTO #name, #species
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #name + ' ' + #species
FETCH NEXT FROM nameSpeciesCursor INTO #name, #species
END
CLOSE nameSpeciesCursor
DEALLOCATE nameSpeciesCursor
cheers