How can I use two select statements in one view - sql

This first select statement gives me a result which i want.
SELECT
b.num,
DATEPART(yyyy, b.dateofstatus) AS yearofinsert,
b.yearbegin,
ac.code,
ac.store,
FROM table1 b LEFT JOIN class ac
ON b.idclass = ac.id LEFT JOIN admin.dbo.DboObj s
ON s.id = b.idobj LEFT JOIN
But when I include this another one statement it gives me an error "problem near WITH", i know that problem is temporary table can't be included in view, but how can i pass that problem, is there any other solution instead of using tmp table?
;WITH tmp(idsubj,DataItem, subject) AS
(
SELECT
idsubj,
LEFT(subject, CHARINDEX(CHAR(10), subject + CHAR(10)) - 1),
STUFF(subject, 1, CHARINDEX(CHAR(10), subject + CHAR(10)), '')
FROM table1 WHERE idobj = 2
UNION all
SELECT
idsubj,
LEFT(subject, CHARINDEX(CHAR(10), subject + CHAR(10)) - 1),
STUFF(subject, 1, CHARINDEX(CHAR(10), subject + CHAR(10)), '')
FROM tmp
WHERE
subject > ''
)
SELECT
idsubj,
DataItem
INTO #a FROM tmp
ORDER BY idsubj
OPTION (maxrecursion 0)
SELECT replace(#a.DataItem,' ',' ') as allbooks, #a.idsubj
FROM #a
LEFT JOIN table1 ON #a.idsubj=table1.idsubj
LEFT JOIN table2 po ON #a.idsubj = po.idsubj
ORDER BY idsubj

Related

Loop never ends in SQL Server using While Exists

While Exists (Select * From Col Where Depth Is Null)
Update T
Set T.Depth = P.Depth + 1,
T.Lineage = P.Lineage + LTrim(Str(T.ParentId, 6, 0)) + '/'
From Col T
Join Col P On T.ParentId = P.Id
Where
P.Depth >= 0
And P.Lineage Is Not Null
And T.Depth Is Null
It looks like you're trying to do a recursive query, and the standard way to do that is with a CTE:
;WITH rec AS(
SELECT c.Id, c.Depth, CAST(c.Id AS varchar(MAX) + '/' AS Lineage
FROM Col c
WHERE c.ParentId IS NULL
UNION ALL
SELECT c1.Id, rec.Depth + 1, rec.Lineage + CAST(c1.id as varchar(10)) + '/'
FROM rec
INNER JOIN Col c1 on rec.Id = c1.ParentId
WHERE rec.Depth < 100 --Limit the recursion, set this to what is appropriate for your data
)
--SELECT * FROM rec --Use this first to see if the data is correct, then:
UPDATE T
SET T.Depth = r.Depth, T.Lineage = r.Lineage
FROM Col T
INNER JOIN rec r ON T.Id = r.Id
For more information about CTE's, you can check this technet link.

sql Id concatenation in sequence in a separate column like running total

I need running Id concatenation just like running balance or total..
Concatenate the previous Ids to current Id row wise just like shown in picture
query is
with relation (Id, [orderSequence])
as
(
select Id,cast(Id as varchar(20))
from [ACChartofAccount]
union all
select p.Id, cast(Cast(r.Id as varchar) + ',' + cast(p.Id as varchar) as varchar(20))
from [ACChartofAccount] p
inner join relation r on p.ParentId = r.Id
)
select Id,orderSequence
from relation
order by orderSequence
You can use below query to get above result.
DECLARE #Table TABLE(ID VARCHAR(10));
INSERT INTO #table(ID) VALUES ('320'),(332),(333),(334),(335);
SELECT mt.ID,
STUFF((
SELECT ', ' + ID
FROM #table t
WHERE t.ID <= mt.ID
FOR XML PATH('')), 1, 2, '') AS oldersequence
FROM #table mt
ORDER BY ID

Concatenate Rows into String with Many to Many Joins

I have a query that is working for almost all my data scenarios...except one. I have a master table, a detail table (with one to many line items), and many description tables that join to the detail table (Code Descriptions, etc). I need to concatenate all detail records into one string value so that I have one record per master record. So if there's 3 details for the master record, all values need to be concatenated into one record to represent the master.
My issue comes when the Master record has multiple detail records but the detail records don't have a match to the description tables 1 to 1. For instance, in my scenario the master record has 3 detail records which only one of the detail records has a description record. So 1 to 3 to 1, Master to Detail to Description. This is causing an issue. When trying to concatenate the records the code is not working because of the NULL value created from the Detail to Description join. The only way I can seem to get this to work is to do a Distinct sub-query and then do my concatenation logic on the outside of that. I feel like there has to be a better way or that I am simply missing something. I provided example code below to show my issue. There are 3 selects that get run. The first is the flat result with all records from the joins. The second is my original logic showing the flaw. The third is a working version that I am hoping someone knows how to do better. I greatly appreciate any help with this issue.
DECLARE #Notification table(
SystemID int NOT NULL,
NotificationID int
);
DECLARE #NotificationItems table(
SystemID int NOT NULL,
NotificationID VARCHAR(100),
LineItem VARCHAR(100)
);
DECLARE #NotificationCauses table(
SystemID int NOT NULL,
NotificationID VARCHAR(100),
LineItem VARCHAR(100),
TestValue VARCHAR(100)
);
INSERT INTO #Notification
SELECT 40,1 UNION
SELECT 40,2 UNION
SELECT 40,3 UNION
SELECT 40,4
INSERT INTO #NotificationItems
SELECT 40,1,1 UNION
SELECT 40,1,2 UNION
SELECT 40,1,3 UNION
SELECT 40,2,1 UNION
SELECT 40,2,2 UNION
SELECT 40,3,1
INSERT INTO #NotificationCauses
SELECT 40,1,1,'Code_A' UNION
SELECT 40,2,1,'Code_B' UNION
SELECT 40,2,2,'Code_C' UNION
SELECT 40,3,1,'Code_D'
--SELECT *
--FROM #Notification
--SELECT *
--FROM #NotificationItems
SELECT *
FROM #Notification AS n
LEFT OUTER JOIN #NotificationItems AS ni
ON n.NotificationID = ni.NotificationID
AND n.SystemID = ni.SystemID
LEFT OUTER JOIN #NotificationCauses AS nc
ON ni.NotificationID = nc.NotificationID
AND ni.SystemID = nc.SystemID
AND ni.LineItem = nc.LineItem
SELECT DISTINCT n.SystemID, n.NotificationID
,SUBSTRING(
(
SELECT DISTINCT
CASE WHEN LTRIM(RTRIM(ni1.LineItem)) <> ISNULL('','') THEN ', '+ni1.LineItem ELSE '' END AS [text()]
FROM #NotificationItems AS ni1
WHERE ni1.SystemID = ni.SystemID AND ni1.NotificationID = ni.NotificationID --AND a1.LineItem = a.LineItem
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [LineItem]
,SUBSTRING(
(
SELECT DISTINCT
CASE WHEN LTRIM(RTRIM(nc1.TestValue)) <> ISNULL('','') THEN ', '+nc1.TestValue ELSE '' END AS [text()]
FROM #NotificationCauses AS nc1
WHERE nc1.SystemID = nc.SystemID AND nc1.NotificationID = nc.NotificationID --AND nc1.LineItem = nc.LineItem
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [TestValues]
FROM #Notification AS n
LEFT OUTER JOIN #NotificationItems AS ni
ON n.SystemID = ni.SystemID
AND n.NotificationID = ni.NotificationID
LEFT OUTER JOIN #NotificationCauses AS nc
ON ni.SystemID = nc.SystemID
AND ni.NotificationID = nc.NotificationID
AND ni.LineItem = nc.LineItem
SELECT DISTINCT SystemID, NotificationID
,SUBSTRING(
(
SELECT DISTINCT
CASE WHEN LTRIM(RTRIM(a1.LineItem)) <> ISNULL('','') THEN ', '+a1.LineItem ELSE '' END AS [text()]
FROM #NotificationItems AS a1
WHERE a1.SystemID = a.SystemID AND a1.NotificationID = a.NotificationID --AND a1.LineItem = a.LineItem
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [LineItem]
,SUBSTRING(
(
SELECT DISTINCT
CASE WHEN LTRIM(RTRIM(a1.TestValue)) <> ISNULL('','') THEN ', '+a1.TestValue ELSE '' END AS [text()]
FROM #NotificationCauses AS a1
WHERE a1.SystemID = a.SystemID AND a1.NotificationID = a.NotificationID --AND a1.LineItem = a.LineItem
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [TestValues]
FROM
(
SELECT DISTINCT n.NotificationID, n.SystemID, ni.LineItem, nc.TestValue
FROM #Notification AS n
LEFT OUTER JOIN #NotificationItems AS ni
ON n.SystemID = ni.SystemID
AND n.NotificationID = ni.NotificationID
LEFT OUTER JOIN #NotificationCauses AS nc
ON ni.SystemID = nc.SystemID
AND ni.NotificationID = nc.NotificationID
AND ni.LineItem = nc.LineItem
) AS a
I have cleared up the query and that's the result
SELECT n.SystemID, n.NotificationID
, SUBSTRING((SELECT COALESCE(', ' + ni.LineItem, '') [text()]
FROM NotificationItems AS ni
WHERE ni.SystemID = n.SystemID
AND ni.NotificationID = n.NotificationID
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [LineItem]
, SUBSTRING((SELECT COALESCE(', ' + nc.TestValue, '') [text()]
FROM NotificationItems AS ni
INNER JOIN NotificationCauses nc
ON ni.SystemID = nc.SystemID
AND ni.NotificationID = nc.NotificationID
AND ni.LineItem = nc.LineItem
WHERE ni.SystemID = n.SystemID
AND ni.NotificationID = n.NotificationID
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [TestValues]
FROM Notification n
Those are the "smell" founded:
the ISNULL('', ''), it really does nothing, replaced with blank string '' (more to come)
the FROM of the main select, there are three table when only one is really used, the unused two are removed, that needed an update of the FROM and WHERE condition subqueries
the DISTINCT of the subqueries, again it does nothing, stripped away
the CASE in the subqueries add a comma before a value, if the trimmed value is not null, that is exactly what COALESCE(', ' + value, '') does (if the trim is needed re-add it)
Everything else is only formatting the query my way, 'cause it's easier to read if it's formatted your way (something like review by refactoring)
Here is a SQLFiddle demo of the cleared query with the data provided

How to declare the columns dynamically in a Select query using PIVOT

I am writing a query to get the address for PersonID. Following query is working for me but it only returns with two Addresses. I want to handle the 'n' number of address with a single query. Is there any way to do this?
Many thanks
SELECT
PersonID, PersonName
[Address1], [Address2]
FROM
(
SELECT
P.PersonID,
P.PersonName,
(ROW_NUMBER() OVER(PARTITION BY P.PersonID ORDER BY A.AddressID)) RowID
FROM tblPerson
INNER JOIN tblAddress AS A ON A.PersonID = P.PersonID
) AS AddressTable
PIVOT
(
MAX(AddressID)
FOR RowID IN ([Address1], [Address2])
) AS PivotTable;
Assuming the following tables and sample data:
USE tempdb;
GO
CREATE TABLE dbo.tblPerson(PersonID INT, PersonName VARCHAR(255));
INSERT dbo.tblPerson SELECT 1, 'Bob'
UNION ALL SELECT 2, 'Charlie'
UNION ALL SELECT 3, 'Frank'
UNION ALL SELECT 4, 'Amore';
CREATE TABLE dbo.tblAddress(AddressID INT, PersonID INT, [Address] VARCHAR(255));
INSERT dbo.tblAddress SELECT 1,1,'255 1st Street'
UNION ALL SELECT 2,2,'99 Elm Street'
UNION ALL SELECT 3,2,'67 Poplar Street'
UNION ALL SELECT 4,2,'222 Oak Ave.'
UNION ALL SELECT 5,1,'36 Main Street, Suite 22'
UNION ALL SELECT 6,4,'77 Sicamore Ct.';
The following query gets the results you want, and shows how it handles 0, 1 or n addresses. In this case the highest number is 3 but you can play with more addresses if you like by adjusting the sample data slightly.
DECLARE #col NVARCHAR(MAX) = N'',
#sel NVARCHAR(MAX) = N'',
#from NVARCHAR(MAX) = N'',
#query NVARCHAR(MAX) = N'';
;WITH m(c) AS
(
SELECT TOP 1 c = COUNT(*)
FROM dbo.tblAddress
GROUP BY PersonID
ORDER BY c DESC
)
SELECT #col = #col + ',[Address' + RTRIM(n.n) + ']',
#sel = #sel + ',' + CHAR(13) + CHAR(10) + '[Address' + RTRIM(n.n) + '] = x'
+ RTRIM(n.n) + '.Address',
#from = #from + CHAR(13) + CHAR(10) + ' LEFT OUTER JOIN xMaster AS x'
+ RTRIM(n.n) + ' ON x' + RTRIM(n.n) + '.PersonID = p.PersonID AND x'
+ RTRIM(n.n) + '.rn = ' + RTRIM(n.n)
FROM m CROSS JOIN (SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_columns) AS n WHERE n.n <= m.c;
SET #query = N';WITH xMaster AS
(
SELECT PersonID, Address,
rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address)
FROM dbo.tblAddress
)
SELECT PersonID, PersonName' + #col
+ ' FROM
(
SELECT p.PersonID, p.PersonName, ' + STUFF(#sel, 1, 1, '')
+ CHAR(13) + CHAR(10) + ' FROM dbo.tblPerson AS p ' + #from + '
) AS Addresses;';
PRINT #query;
--EXEC sp_executesql #query;
If you print the SQL you will see this result:
;WITH xMaster AS
(
SELECT PersonID, Address,
rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address)
FROM dbo.tblAddress
)
SELECT PersonID, PersonName,[Address1],[Address2],[Address3] FROM
(
SELECT p.PersonID, p.PersonName,
[Address1] = x1.Address,
[Address2] = x2.Address,
[Address3] = x3.Address
FROM dbo.tblPerson AS p
LEFT OUTER JOIN xMaster AS x1 ON x1.PersonID = p.PersonID AND x1.rn = 1
LEFT OUTER JOIN xMaster AS x2 ON x2.PersonID = p.PersonID AND x2.rn = 2
LEFT OUTER JOIN xMaster AS x3 ON x3.PersonID = p.PersonID AND x3.rn = 3
) AS Addresses;
If you execute it, you will see this:
I know the query to get here is an ugly mess, but your requirement dictates it. It would be easier to return a comma-separated list as I suggested in my comment, or to have the presentation tier deal with the pivoting.

How to make 2 rows into single row in sql

I have a query
example
Title Description
A XYZ
A ABC
now i want a sql query so that i can get a single row
Output :
Title Description
A XYZ | ABC
Declare #tbl table(Title nvarchar(1),[Description] nvarchar(100))
Insert into #tbl values('A','XYZ');
Insert into #tbl values('A','ABC');
Insert into #tbl values('A','PQR');
DECLARE #CSVList varchar(100)
SELECT #CSVList = COALESCE(#CSVList + ' | ', '') +
[Description]
FROM #tbl
WHERE Title='A'
SELECT #CSVList
declare #table table (i int, a varchar(10))
insert into #table
select 1, 'ABC' union all
select 1, 'XYZ' union all
select 2, '123'
select t.i,
max(stuff(d.i, 1, 1, '')) [iList]
from #table t
cross
apply ( select '|' + a
from #table [tt]
where t.i = tt.i
for xml path('')
) as d(i)
group
by t.i;
In mysql there is a group_concat function, that can help you.
Use it like this:
SELECT Title,GROUP_CONCAT(Description) FROM table_name GROUP BY Title
The output will be
Title Description
A XYZ,ABC
Then you can replace "," with "|" if you want(it can be done with replace function)
For 2 rows you can self join in SQL Server. This avoids the assorted "concatenate rows into a column" tricks. You can use a LEFT JOIN and NULL handling too for 1 or 2 rows
SELECT
T1.Title,
T1.Description + '|' + T2.Description
FROM
MyTable T1
JOIN
MyTable T2 ON T1.Title = T2.Title
SELECT
T1.Title,
T1.Description + ISNULL('|' + T2.Description, '') --COALESCE for the pedants)
FROM
MyTable T1
LEFT JOIN
MyTable T2 ON T1.Title = T2.Title
If you are using SQL Server, try this: How to return 1 single row data from 2 different tables with dynamic contents in sql