SQL Query To Get Structured Result - sql

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.

Related

Procedure with cursor has missing output

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).

SQL recursive udf always returns null

Create Table Employees
(
Employee varchar(10),
Manager varchar(10)
);
Insert into Employees
values
('Charlie',null),
('Peter','James'),
('Elai',null),
('Graham','Emanuel'),
('Amanda','Charlie'),
('Sen','Graham'),
('Emanuel',null),
('James','Amanda'),
('Elai',null),
('Victor','Elai');
Above "Employees" table contains employee and employee's manager name. When trying to retrieve comma separated hierarchy of a employee using below function, the result is always null.
for example :
employee 'Victor', hierarchy/result should be "Victor, Elai".
Could anyone point out what am I doing wrong in below UDF.
Create Function EmployeeHierarchy(#employeeName varchar(20))
Returns varchar(100)
AS
Begin
Declare #commaSeparatedHierarchy varchar(100);
Declare #manager varchar(20);
if(#employeeName is not null)
Begin
Select #manager=Manager from Employees where Employee=#employeeName;
Set #commaSeparatedHierarchy=dbo.EmployeeHierarchy(#manager)+','+#manager;
End
return #commaSeparatedHierarchy;
End;
First & foremost, you DO NOT want to create this as a scalar function. Their performance is horrible any udf you create, should be created as an inline table valued function. The following should do what you're looking for...
-- the test data...
USE tempdb;
GO
IF OBJECT_ID('tempdb.dbo.Employee', 'U') IS NOT NULL
DROP TABLE dbo.Employee;
CREATE TABLE dbo.Employee (
Employee varchar(10),
Manager varchar(10)
);
INSERT dbo.Employee (Employee, Manager) VALUES
('Charlie',null),
('Peter','James'),
('Elai',null),
('Graham','Emanuel'),
('Amanda','Charlie'),
('Sen','Graham'),
('Emanuel',null),
('James','Amanda'),
('Elai',null),
('Victor','Elai');
SELECT * FROM dbo.Employee e;
iTVF code...
CREATE FUNCTION dbo.EmployeeHierarchy
(
#employeeName varchar(20)
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
WITH
cte_Recur AS (
SELECT
CSH = CAST(CONCAT(e.Employee, ', ' + e.Manager) AS VARCHAR(1000)),
e.Manager,
NodeLevel = 1
FROM
dbo.Employee e
WHERE
e.Employee = #employeeName
UNION ALL
SELECT
CSH = CAST(CONCAT(r.CSH, ', ' + e.Manager) AS VARCHAR(1000)),
e.Manager,
NodeLevel = r.NodeLevel + 1
FROM
dbo.Employee e
JOIN cte_Recur r
ON e.Employee = r.Manager
WHERE
e.Manager IS NOT NULL
)
SELECT
commaSeparatedHierarchy = MAX(r.CSH)
FROM
cte_Recur r;
GO
Sample execution...
SELECT
eh.commaSeparatedHierarchy
FROM
dbo.EmployeeHierarchy('peter') eh;
... and the results...
commaSeparatedHierarchy
------------------------------
Peter, James, Amanda, Charlie

Inserting a temporary table with cursor search function to an existing SQL query

I am needing help with trying to join a there two queries.
The first query is my main query for the report i am trying to build.
PARAMETERS [DocumentNo] String "", [hideComments] boolean False;
Select cus.name, cus.addra, cus.addrb, cus.addrc, cus.addrd, cus.addre, cus.pcode as PostCode, br.name As BranchName, br.addra As BrAddrA, br.addrb As BrAddrB,
br.addrc As BrAddrC, br.addrd As BrAddrD, br.addre As BrAddrE, br.postcode As postcodebr, br.Phonenumber as brphonenumber, v.make as vmake, v.YoM as vyear, v.model as vmodel, v.carcolour as vcolor, v.pkey as license, v.state as vstate, V.mileage as mileageout
,h.datetime, h.document, h.acct, h.inits, h.payref, h.corder, h.goods, h.vat,
(Case IsNull(p.supppart,'') when '' then l.part else p.supppart end) part, l.bopdes,
l.qty, l.unit, c.a2 As 'WorkOrderComments'
from jheads h
inner join jlines l on l.document = h.document
inner join customer cus on cus.keycode = h.acct
left join plines p on l.porder = p.document + '/' + cast(p.seqno as varchar(3))
left join codes c on c.keycode= h.branch and c.prefix='WA' and c.subkey1=0
left join branches br on br.branch = h.branch
left join vehicles v on v.Custacnum = h.acct
where H.Document= [DocumentNo]
The information i am needing to add to this report query is; i need the due date for two types based in the "reminders" table. How this information works is that the type column is populated with one of two options 'EMSN or 'INSP. the "VRM" coloumn from this table related to the "pkey" from vehicles table which is all ready in the first query. The VRM is the license of related to an order, but a license can have multiple EMSN and INSP records, there records are sorted sequentically and i need the latest records to be merged into the report for each type ( so i need two record specifically drawn out)
The query i have used to gather this information and temporary store this is
use [Masterdatabase]
GO
DECLARE #source TABLE
(
CustAcNum VARCHAR(255) NOT NULL,
SeqNo INT NOT NULL,
Class VARCHAR(255),
[type] VARCHAR(255) NOT NULL,
Vrm VARCHAR(12),
Duedate DATETIME,
VehicleId UNIQUEIDENTIFIER
);
DECLARE #filtered TABLE
(
CustAcNum VARCHAR(255) NOT NULL,
SeqNo INT NOT NULL,
Class VARCHAR(255),
[type] VARCHAR(255) NOT NULL,
Vrm VARCHAR(12),
Duedate DATETIME,
VehicleId UNIQUEIDENTIFIER
);
INSERT INTO #source
SELECT v.CustAcNum, r.SeqNo, r.[Class], r.[type], r.Vrm, r.Duedate, r.VehicleId
FROM dbo.Vehicles AS v
INNER JOIN dbo.Reminders AS r ON r.VRM = v.Pkey
WHERE r.[Type] = 'EMSN'
GROUP BY v.CustAcNum, r.SeqNo, r.[Class], r.[type], r.Vrm, r.Duedate, r.VehicleId
UNION
SELECT v.CustAcNum, r.SeqNo, r.[Class], r.[type], r.Vrm, r.Duedate, r.VehicleId
FROM dbo.Vehicles AS v
INNER JOIN dbo.Reminders AS r ON r.VRM = v.Pkey
WHERE r.[Type] = 'INSP'
GROUP BY v.CustAcNum, r.SeqNo, r.[Class], r.[type], r.Vrm, r.Duedate, r.VehicleId
ORDER BY v.CustAcNum, r.Seqno DESC;
DECLARE
#custAcNum VARCHAR(255)
,#seqNo INT
,#class VARCHAR(255)
,#type VARCHAR(255)
,#vrm VARCHAR(12)
,#duedate DATETIME
,#vehicleId UNIQUEIDENTIFIER
DECLARE source_cursor CURSOR
FAST_FORWARD
FOR SELECT * FROM #source WHERE NULLIF(ltrim(rtrim(CustAcNum)), '') IS NOT NULL;
OPEN source_cursor
FETCH NEXT FROM source_cursor
INTO #custAcNum, #seqNo, #class, #type, #vrm, #duedate, #vehicleId;
WHILE ##FETCH_STATUS = 0
BEGiN
IF NOT EXISTS (SELECT 1 FROM #filtered WHERE CustAcNum = #custAcNum AND [type] = #type)
BEGIN
INSERT INTO #filtered
VALUES (#custAcNum, #seqNo, #class, #type, #vrm, #duedate, #vehicleId);
END
FETCH NEXT FROM source_cursor
INTO #custAcNum, #seqNo, #class, #type, #vrm, #duedate, #vehicleId;
END
CLOSE source_cursor;
DEALLOCATE source_cursor;
select * from #filtered;
I'm now needing to join these two together and be able to extract the due date out of them for both type's.
I'm stuck on this so any help i would appreciate it.

SQL Server : print out cursor values

I want to be able to print out or output the values from a cursor for my stored procedure's. I'm having a hard time trying to figure out how to do this. I need to output my values onto a sheet like a report about which customers have paid and which haven't. A comparison would be great.
Here are my stored procedures for the customers who haven't paid:
CREATE PROC [dbo].[AdminReport1]
AS
BEGIN
SELECT
booking.bookingID, booking.totalCost,
booking.bookingDate, booking.paymentConfirmation,
customers.customersID,
customers.firstname, customers.surname,
customers.contactNum
FROM
booking
INNER JOIN
customers ON booking.customerID = customers.customersID
WHERE
paymentConfirmation = 'False'
ORDER BY
bookingDate ASC
END
GO
Here are my stored procedures for the customers who HAVE paid:
CREATE PROC [dbo].[AdminReport2]
AS
BEGIN
SELECT
booking.bookingID, booking.totalCost,
booking.bookingDate, booking.paymentConfirmation,
customers.customersID,
customers.firstname, customers.surname,
customers.contactNum
FROM
booking
INNER JOIN
customers ON booking.customerID = customers.customersID
WHERE
paymentConfirmation = 'TRUE'
ORDER BY
bookingDate ASC
So I need a cursor to print out my values. If anyone could help it would be much appreciated. An example with how to do this in code would be appreciated.
While I'm not convinced this is the most efficient way to do it (it would be better for SQL Server to feed the data to something designed to make display data; SSRS or even to Excel), here is what I would do as a start:
--Create somewhere to put the proc data and fill it. This will give us something tangible to query against.
CREATE TABLE #NotPaid
(
bookingID INT ,
totalCost DECIMAL(7, 2) ,
bookingDate DATE ,
paymentConfirmation VARCHAR(50) ,
customersID INT ,
firstname VARCHAR(50) ,
surname VARCHAR(50) ,
contactNum VARCHAR(50)
)
CREATE TABLE #HasPaid
(
bookingID INT ,
totalCost DECIMAL(7, 2) ,
bookingDate DATE ,
paymentConfirmation VARCHAR(50) ,
customersID INT ,
firstname VARCHAR(50) ,
surname VARCHAR(50) ,
contactNum VARCHAR(50)
)
INSERT #NotPaid
EXEC AdminReport1
INSERT #HasPaid
EXEC AdminReport2
--Variables for use in our cursor. I'm only loading one table up as a demonstration.
DECLARE #bookingID INT ,
#totalCost DECIMAL(7, 2) ,
#bookingDate DATE ,
#paymentConfirmation VARCHAR(50) ,
#customersID INT ,
#firstname VARCHAR(50) ,
#surname VARCHAR(50) ,
#contactNum VARCHAR(50)
DECLARE #Library CURSOR
SET
#Library = CURSOR FOR
SELECT bookingID ,
totalCost ,
bookingDate ,
paymentConfirmation ,
customersID ,
firstname,
surname ,
contactNum FROM #HasPaid
--Run the cursor and print out the variables as we loop again. Any formatting will need to be done in here. Again, I'm not sure this is the best way to achieve what you are trying to achieve.
OPEN #Library
FETCH NEXT FROM #getProductID INTO #bookingID, #totalCost, #bookingDate,
#paymentConfirmation, #customersID, #firstname, #surname, #contactNum
PRINT 'I''m a header line'
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #firstname + ' Hasnt paid! His booking date is ' + STR(#bookingDate)
+ '. This is the middle part'
FETCH NEXT FROM #Library INTO #bookingID, #totalCost, #bookingDate,
#paymentConfirmation, #customersID, #firstname, #surname, #contactNum
END
PRINT 'I''m at the bottom'
CLOSE #Library
DEALLOCATE #Library
GO
This should give you a fairly good starting place.
In terms of general efficiency, it would be better to just have the one proc and you pass in the information you want out, so, pass in the fact you just want the Paids, or just want the NotPaids, or everyone. And just to be a bore about it, SQL isn't really the place to be doing this type of formatting. There are much better tools out there for this!
I would suggest staying away from cursors unless there is a specific valid reason for using them. You could simplify this slightly by having a view which has the columns you are looking for
CREATE VIEW [dbo].[AdminReport]
AS
BEGIN
SELECT
b.bookingID,
b.totalCost,
b.bookingDate,
b.paymentConfirmation,
c.customersID,
customers.firstname,
c.surname,
c.contactNum,
paymentConfirmation
FROM
booking b
INNER JOIN customers c
ON b.customerID= c.customersID
--Where
--paymentConfirmation = 'False'
ORDER BY
bookingDate ASC
END
GO
And then you can just select the records paid records as
Select * from AdminReport where paymentConfirmation = 'TRUE'
and the unpaid ones as
Select * from AdminReport where paymentConfirmation = 'FALSE'

Display a resultset where each cell is based on different condition using stored procedure

I have a table from which I query data to display resultset using stored procedure. I also have a value to be given in the where condition that keeps changing for each and every cell and that parameter is not available in the table from which I have to query. As of now, I have hardcoded the for that particular parameter. My resultset should consist of 7 rows and 16 columns. Is there any optimistic way instead of hardcoding it ? Any help is appreciated.
Here is the temp table I ve hardcoded:
create table #temp_financials(iden_val int identity(1,1) ,
categ varchar(100),Retail_RDR varchar(100),Avg_Price_RDR varchar(100),
GPVR_RDR varchar(100),
L_RDR varchar(100),
L_Avg_Price varchar(100),L_GPVL varchar(100),
C_RDR varchar(100),C_Avg_Price varchar(100),C_GPVR varchar(100),
C_Rgn_GPVR varchar(100),C_Nat_GPVR varchar(100),
C_Lease_Penet varchar(100),C_Rgn_Penet varchar(100))
insert into #temp_financials(categ,Retail_RDR ,Avg_Price_RDR , GPVR_RDR ,
L_RDR ,L_Avg_Price ,L_GPVL ,
C_RDR ,C_Avg_Price ,C_GPVR ,C_Rgn_GPVR ,C_Nat_GPVR ,
C_Lease_Penet ,C_Rgn_Penet )
values('Ttl Sum',
'B9720','B9996','B9776','B9722','B9997','B9791','B9733','B10003','B9806','B9806 ','B9806','B9885','B9885' )
insert into #temp_financials(categ,Retail_RDR ,Avg_Price_RDR , GPVR_RDR ,
L_RDR ,L_Avg_Price ,L_GPVL ,
C_RDR ,C_Avg_Price ,C_GPVR ,C_Rgn_GPVR ,C_Nat_GPVR ,
C_Lease_Penet ,C_Rgn_Penet )
values ('B9870','B9773','4042A','B9998','B9788',
'B9872','B2090','B9803','B9803','B9803','B10004','B10004')
Here is the table with which I ve to join:
while(#loop_var<=#count_var)
begin
select t.categ,Retail_RDR=w1.CMValue,Avg_Price_RDR=w2.CMValue,
GPVR_RDR=w3.CMValue,L_RDR=w4.CMValue,
from westernunion w1 join #temp_financials t on
w1.acct_no=t.retail_RDR left outer join
westernunion w2 on w2.acct_no=t.avg_price_rdr
left outer join westernunion w3 on w3.acct_no=t.GPVR_RDR
left outer join westernunion w4 on w4.acct_no=t.L_RDR
where t.iden_val=#loop_var
set #loop_var=#loop_var+1
end
Use dynamic SQL query:
Declare #vQuery nvarchar(max),
#vWhereClasue varchar(500)
SET #vQuery = 'Select top 7 col1,col2 ....col16 from ... where ' + #vWhereClasue
exec sp_executesql #vQuery