I need to get the following code to work, however, it is giving me an error at the last Select statement. The error that I am receiving is:
Incorrect syntax near the keyword 'select'.
Could someone please assist in resolving this issue? Thank You.
declare #Lookup table(
Id int identity(1, 1)
, SongTitle nvarchar(512)
)
insert into #Lookup(SongTitle)
select *
from (
values('Deuce')
, ('Strutter')
, ('Black_Diamond')
, ('Parasite')
, ('Strange_Ways')
, ('Rock_Bottom')
, ('God_of_Thunder')
, ('Love_Gun')
, ('She')
, ('I_Stole_Your_Love')
)
select Albums.AlbumName
, Songs.SongTitle
, Songs.Writers
, Songs.Vocals
, Songs.SID
, Songs.TheTime
from Albums A
inner join Songs S
on A.AID = S.AID
inner join #Lookup L
on L.SongTitle = S.SongTitle
order by L.Id
You need to provide an alias for your derived tables
insert into #Lookup(SongTitle)
select *
from (
values('Deuce')
, ('Strutter')
, ('Black_Diamond')
, ('Parasite')
, ('Strange_Ways')
, ('Rock_Bottom')
, ('God_of_Thunder')
, ('Love_Gun')
, ('She')
, ('I_Stole_Your_Love')
) AS v; -- <<< provide alias for derived tables
If you assign an alias to a table, use the alias instead of the table name.
select A.AlbumName -- <<< use alias instead of table name
, S.SongTitle -- <<< use alias instead of table name
, S.Writers
, S.Vocals
, S.SID
, S.TheTime
from Albums A
inner join Songs S
on A.AID = S.AID
inner join #Lookup L
on L.SongTitle = S.SongTitle
order by L.Id;
Related
I am trying to retrieve some data from joined tables in JSON format.
Currently I'm trying this:
select top(1)
a.IdUser ,
b.UserName ,
a.IdGroup ,
c.Title
from UserGroupMembers as a
inner join users as b on a.IdUser= b.iduser
inner join UserGroups as c on a.IdGroup = c.IdUserGroup
for json auto
which returns this:
[{"IdUser":1,"IdGroup":8,"b":[{"UserName":"User1","c":[{"Title":"Group1"}]}]}]
while I need to get this:
[{"IdUser":1,"IdGroup":8, "UserName":"User1", "Title":"Group1" }]
or at least this:
[{"IdUser":1,"IdGroup":8,"b":[{"UserName":"User1"}] ,"c":[{"Title":"Group1"}] }]
You need to use FOR JSON PATH instead of FOR JSON AUTO:
Tables:
CREATE TABLE UserGroupMembers (
IdUser int,
IdGroup int
)
CREATE TABLE Users (
IdUser int,
UserName nvarchar(50)
)
CREATE TABLE UserGroups (
IdUserGroup int,
Title nvarchar(100)
)
INSERT INTO UserGroupMembers(IdUser, IdGroup) VALUES (1, 8)
INSERT INTO Users(IdUser, UserName) VALUES (1, N'User1')
INSERT INTO UserGroups(IdUserGroup, Title) VALUES (8, N'Group1')
Statement:
SELECT TOP (1)
a.IdUser ,
b.UserName,
a.IdGroup,
c.Title
FROM UserGroupMembers AS a
INNER JOIN Users AS b on a.IdUser= b.IdUser
INNER JOIN UserGroups AS c on a.IdGroup = c.IdUserGroup
FOR JSON PATH
Result:
[{"IdUser":1,"UserName":"User1","IdGroup":8,"Title":"Group1"}]
Note, that with FOR JSON PATH you may use dot-separated column names to generate JSON with nested objects.
SELECT TOP (1)
a.IdUser ,
b.UserName AS [b.UserName],
a.IdGroup,
c.Title AS [c.Title]
FROM UserGroupMembers AS a
INNER JOIN Users AS b on a.IdUser= b.IdUser
INNER JOIN UserGroups AS c on a.IdGroup = c.IdUserGroup
FOR JSON PATH
Result:
[{"IdUser":1,"b":{"UserName":"User1"},"IdGroup":8,"c":{"Title":"Group1"}}]
The simplest way
select *
from (
select top(1)
a.IdUser ,
b.UserName ,
a.IdGroup ,
c.Title
from UserGroupMembers as a
inner join users as b on a.IdUser= b.iduser
inner join UserGroups as c on a.IdGroup = c.IdUserGroup
) t
for json auto
I am trying to make a CTE with 3 levels. Can this be done?
I am using this SQL statement for 2 levels. Can you help me to add a third level?
WITH ProjectReport(ParentProject, ProjectNr, [Level]) AS
(
SELECT ParentProject, Projectnr, 0 as [Level]
FROM prproject
WHERE ParentProject IS NULL
UNION ALL
SELECT e.ParentProject, e.ProjectNr, [Level]+1
FROM PrProject AS e
INNER JOIN ProjectReport AS d
ON e.ParentProject = d.ProjectNr
)
SELECT ParentProject, ProjectNr, [Level]
FROM ProjectReport
WHERE [Level] <= 2 and ParentProject = 'cl3264';
It doesn't look like you really need a recursive CTE for this. It seems like 2 joins would do the trick (depending on what tables you have).
SELECT A.ProjectNr
, B.ProjectNr
, C.ProjectNr
FROM PROJECTS A
INNER JOIN PROJECTS B ON A.ProjectNr = B.ParentProject
INNER JOIN PROJECTS C ON B.ProjectNr = C.ParentProject
WHERE A.ProjectNr = 'CL3264'
This should also work even if you need to join the same table.
You can use the below script to check out the results:
CREATE TABLE #PROJECTS (ProjectNr varchar(30), ParentProject varchar(30));
INSERT INTO #PROJECTS (ProjectNr, ParentProject) values ('CL3264', NULL)
, ('CL3264-B', 'Cl3264')
, ('CL3264-C1', 'Cl3264')
, ('CL3264-C2', 'Cl3264')
, ('CL3264-C3', 'Cl3264')
, ('CL3264-F1', 'Cl3264')
, ('CL3264-G1', 'Cl3264')
, ('CL3264-G2', 'Cl3264')
, ('CL3264-P', 'Cl3264')
, ('PR1700000468', 'CL3264-B')
, ('PR1700000469', 'CL3264-C1')
, ('PR1700000474', 'CL3264-C2')
, ('PR1700000475', 'CL3264-C3')
, ('PR1700000476', 'CL3264-F1')
, ('PR1700000477', 'CL3264-G1')
, ('PR1700000478', 'CL3264-G2')
, ('PR1700000479', 'CL3264-P')
, ('PR1700000999', 'CL3264-X')
, ('PR1700009999', 'CL3264-Y')
, ('CL3264-Y', 'CL2360') -- purposely added to see that the filtering works
, ('CL3264-X', 'CL2360') -- purposely added to see that the filtering works
, ('CL2360', NULL) -- purposely added to see that the filtering works
SELECT A.ProjectNr
, B.ProjectNr AS Project_Level2
, C.ProjectNr AS Project_Level3
FROM #PROJECTS A
INNER JOIN #PROJECTS B ON A.ProjectNr = B.ParentProject
INNER JOIN #PROJECTS C ON B.ProjectNr = C.ParentProject
WHERE A.ProjectNr = 'CL3264'
You can see the output of the script / query below:
You can have multiple CTEs in one query, as well as reuse a CTE:
WITH CTE1 AS (
SELECT TOP 2 Name FROM Sales.Store
),
CTE2 AS (
SELECT TOP 2 ProductNumber, Name FROM Production.Product
),
CTE3 AS (
SELECT TOP 2 Name FROM Person.ContactType
)
SELECT * FROM CTE1,CTE2,CTE3
-- Or use INNER JOIN, LEFT JOIN instead of Cartesian Joins
Just a question regards to temp tables and declaring table. If I change the temp tables 'ChangedData' and 'PackageDatatoProcess' to their own variables '#ChangedData' and '#PackageDatatoProcess', can I ask how I am suppose to change the select into statement as I have not quite done this before. Virtually I told that we can declare tables rather than using the select into but just need a bit of help with this:
select distinct * into #PackageDataToProcess from #ChangedData pp
outer apply (
select pk.Reference, pjl.PackageToJournalLinkId, j.CreatedDate, pccl.PackageCostChangeLogId from Jet2Holidays.dbo.Package pk
inner join Jet2Holidays.dbo.PackageToJournalLink pjl on pk.PackageId = pjl.PackageId
inner join Jet2Holidays.dbo.Journal j on pjl.JournalId = j.JournalId
and j.PrincipalName= iif(#AllowNonSupportChanges = 0, 'HolidaysSupport', j.PrincipalName)
inner join Jet2Holidays.dbo.BusinessProcess bp on pjl.BusinessProcessId = bp.BusinessProcessId
and bp.[Description] = iif(#AllowNonSupportChanges = 0, 'CallCentreAction', bp.[Description])
left outer join Jet2Holidays.dbo.PackageCostChangeLog pccl on pccl.PackageToJournalLinkId = pjl.PackageToJournalLinkId
where pk.Reference = pp.PackageReference
and pp.JournalID = pjl.JournalId
) as packageData
First, you declare your variable tables like so:
DECLARE #PackageDataToProcess TABLE
(
Reference UNIQUEIDENTIFIER
, PackageToJournalLinkId INT
, CreatedDate DATETIME
, PackageCostChangeLogId INT
, {other columns here}
)
DECLARE #ChangedData TABLE
(
Reference UNIQUEIDENTIFIER
, PackageToJournalLinkId INT
, CreatedDate DATETIME
, PackageCostChangeLogId INT
, {other columns here}
)
At this point you can populate your #ChangedData table like so:
INSERT #ChangedData ( Reference, PackageToJournalLinkId, CreatedDate, PackageCostChangeLogId, {other columns})
SELECT Reference, PackageToJournalLinkId, CreatedDate, PackageCostChangeLogId, {other columns}
FROM ChangedDataSource -- Table, Procedure, Function
And then you can run your code by substituting #PackageDataToProcess for #PackageDataToProcess. Here it is again with a slight re-write (from the original):
INSERT #PackageDataToProcess
select distinct pp.* from #ChangedData pp
outer apply (
select pk.Reference, pjl.PackageToJournalLinkId, j.CreatedDate, pccl.PackageCostChangeLogId from Jet2Holidays.dbo.Package pk
inner join Jet2Holidays.dbo.PackageToJournalLink pjl on pk.PackageId = pjl.PackageId
inner join Jet2Holidays.dbo.Journal j on pjl.JournalId = j.JournalId
and j.PrincipalName= iif(#AllowNonSupportChanges = 0, 'HolidaysSupport', j.PrincipalName)
inner join Jet2Holidays.dbo.BusinessProcess bp on pjl.BusinessProcessId = bp.BusinessProcessId
and bp.[Description] = iif(#AllowNonSupportChanges = 0, 'CallCentreAction', bp.[Description])
left outer join Jet2Holidays.dbo.PackageCostChangeLog pccl on pccl.PackageToJournalLinkId = pjl.PackageToJournalLinkId
where pk.Reference = pp.PackageReference
and pp.JournalID = pjl.JournalId
) as packageData
Your declared tabled will go out of scope in a similar manner to the way your non-global temporary table do.
I have a query that I am using to pull in data from different tables. I have broken downthe query into a few different parts to make like a little easier. The problem is that when an ID number exists for sure in both places the LEFT JOIN does not always match them up, somtimes it does sometimes it does not.
All of the ID numbers are of type INT so I know all the data types are the same. I tried to use COLLATE SQL_Latin_General_Pref_CP1_CI_AS in the join statement but that is invalid for data of type INT was the error I received. OK fine, but I am really stuck as I don't know where to proceede from here other than dumping into excel and doing a vlookup.
Here is what I have:
DECLARE #sd DATETIME;
DECLARE #ed DATETIME;
SET #sd = '2014-01-01';
SET #ed = '2015-10-01';
DECLARE #denials_write_offs TABLE (
pk INT IDENTITY(1, 1) PRIMARY KEY
, pt_id INT
, bill_no INT
, denials FLOAT
)
INSERT INTO #denials_write_offs
SELECT a.pt_id
, a.bill_no
, a.denials_woffs
FROM (
SELECT CAST(pt_id AS INT) pt_id
, CAST(bill_no AS INT) bill_no
, SUM(tot_pay_adj_amt) AS denials_woffs
FROM smsmir.mir_pay
JOIN smsdss.c_Softmed_Denials_Detail_v
ON smsmir.mir_pay.pt_id = smsdss.c_Softmed_Denials_Detail_v.bill_no
WHERE discharged >= #sd
AND discharged < #ed
AND LEFT(smsmir.mir_pay.pay_cd, 4) = '0974'
GROUP BY pt_id
, bill_no
) A
--------------------------------------
DECLARE #EDTBL TABLE (
ACCOUNT INT
, ED_MD VARCHAR(MAX)
)
INSERT INTO #EDTBL
SELECT Z.*
FROM (
SELECT CAST(ACCOUNT AS INT) ACCOUNT
, ED_MD
FROM SMSDSS.c_Wellsoft_Rpt_tbl
) Z
----------------------------------------
DECLARE #TmpDenialsTbl TABLE (
PK INT IDENTITY(1, 1) PRIMARY KEY
, BILL_NO INT
...
...
...
)
INSERT INTO #TmpDenialsTbl
SELECT *
FROM (
SELECT bill_no
...
...
...
)
So as you can see, from the above every pt_id or bill_no is put into a table as an INT but I cannot for the life of me figure out why sometimes I get a match on my LEFT JOIN and why sometimes I do not. I did pull data from the #EDMD table and get the account number I was looking for but it did not hit on the left join below:
FROM #TmpDenialsTbl A
LEFT OUTER JOIN #denials_write_offs D
ON A.bill_no = d.pt_id
LEFT OUTER JOIN #EDTBL C
ON C.Account = D.bill_no
LEFT OUTER JOIN #USERTBL F
ON A.CERM_RVWR_ID = F.login_id
AND F.RN = 1
Example of what I am doing and what I get back
DECLARE #TmpDenials TABLE (
PT_ID INT
)
INSERT INTO #TmpDenials
SELECT A.*
FROM (
SELECT CAST(PT_ID AS INT) PT_ID
FROM SOME_TABLE
) A
DECLARE #EDMD TABLE (
PT_ID INT
EDMD VARCHAR(MAX)
)
INSERT INTO #EDMD
SELECT B.*
FROM (
SELECT CAST(PT_ID AS INT) PT_ID
EDMD
FROM SOME_OTHER_TABLE
)B
SELECT * FROM #TmpDenials
PT_ID |
123456789 |
SELECT * FROM #EDMD
PT_ID | ED_MD
123456789 | Dr. Emergency Room
SELECT *
FROM #TmpDenials A
LEFT OUTER JOIN #EDMD B
ON A.PT_ID = B.PT_ID
A.PT_ID | B.PT_ID | ED MD
123456789 | NULL | NULL
I'm not sure if this is the cause of your problem or not, but this condition is potentially suspicious:
FROM #TmpDenialsTbl A LEFT OUTER JOIN
#denials_write_offs D
ON A.bill_no = d.pt_id LEFT OUTER JOIN
#EDTBL C
ON C.Account = D.bill_no LEFT OUTER JOIN
--------^
#USERTBL F
ON A.CERM_RVWR_ID = F.login_id AND F.RN = 1
If there is no match to the C table form A, then this will always fail to match. I'm not sure if this is the intended behavior.
The other option is that a WHERE clause is filtering out the rows that you want.
Note: When you use table aliases, you should use abbreviations for the table names, so i, wo, e, and u are better than the arbitrary letters a, d, c, and f.
I'm trying to join three tables to pull back a list of distinct blog posts with associated assets (images etc) but I keep coming up a cropper. The three tablets are tblBlog, tblAssetLink and tblAssets. The Blog tablet hold the blog, the asset table holds the assets and the Assetlink table links the two together.
tblBlog.BID is the PK in blog, tblAssets.AID is the PK in Assets.
This query works but pulls back multiple posts for the same record. I've tried to use select distinct and group by and even union but as my knowledge is pretty poor with SQL - they all error.
I'd like to also discount any assets that are marked as deleted (tblAssets.Deleted = true) but not hide the associated Blog post (if that's not marked as deleted). If anyone can help - it would be much appreciated! Thanks.
Here's my query so far....
SELECT dbo.tblBlog.BID,
dbo.tblBlog.DateAdded,
dbo.tblBlog.PMonthName,
dbo.tblBlog.PDay,
dbo.tblBlog.Header,
dbo.tblBlog.AddedBy,
dbo.tblBlog.PContent,
dbo.tblBlog.Category,
dbo.tblBlog.Deleted,
dbo.tblBlog.Intro,
dbo.tblBlog.Tags,
dbo.tblAssets.Name,
dbo.tblAssets.Description,
dbo.tblAssets.Location,
dbo.tblAssets.Deleted AS Expr1,
dbo.tblAssetLink.Priority
FROM dbo.tblBlog
LEFT OUTER JOIN dbo.tblAssetLink
ON dbo.tblBlog.BID = dbo.tblAssetLink.BID
LEFT OUTER JOIN dbo.tblAssets
ON dbo.tblAssetLink.AID = dbo.tblAssets.AID
WHERE ( dbo.tblBlog.Deleted = 'False' )
ORDER BY dbo.tblAssetLink.Priority, tblBlog.DateAdded DESC
EDIT
Changed the Where and the order by....
Expected output:
tblBlog.BID = 123
tblBlog.DateAdded = 12/04/2015
tblBlog.Header = This is a header
tblBlog.AddedBy = Persons name
tblBlog.PContent = *text*
tblBlog.Category = Category name
tblBlog.Deleted = False
tblBlog.Intro = *text*
tblBlog.Tags = Tag, Tag, Tag
tblAssets.Name = some.jpg
tblAssets.Description = Asset desc
tblAssets.Location = Location name
tblAssets.Priority = True
Use OUTER APPLY:
DECLARE #b TABLE ( BID INT )
DECLARE #a TABLE ( AID INT )
DECLARE #ba TABLE
(
BID INT ,
AID INT ,
Priority INT
)
INSERT INTO #b
VALUES ( 1 ),
( 2 )
INSERT INTO #a
VALUES ( 1 ),
( 2 ),
( 3 ),
( 4 )
INSERT INTO #ba
VALUES ( 1, 1, 1 ),
( 1, 2, 2 ),
( 2, 1, 1 ),
( 2, 2, 2 )
SELECT *
FROM #b b
OUTER APPLY ( SELECT TOP 1
a.*
FROM #ba ba
JOIN #a a ON a.AID = ba.AID
WHERE ba.BID = b.BID
ORDER BY Priority
) o
Output:
BID AID
1 1
2 1
Something like:
SELECT b.BID ,
b.DateAdded ,
b.PMonthName ,
b.PDay ,
b.Header ,
b.AddedBy ,
b.PContent ,
b.Category ,
b.Deleted ,
b.Intro ,
b.Tags ,
o.Name ,
o.Description ,
o.Location ,
o.Deleted AS Expr1 ,
o.Priority
FROM dbo.tblBlog b
OUTER APPLY ( SELECT TOP 1
a.* ,
al.Priority
FROM dbo.tblAssetLink al
JOIN dbo.tblAssets a ON al.AID = a.AID
WHERE b.BID = al.BID
ORDER BY al.Priority
) o
WHERE b.Deleted = 'False'
You cannot join three tables unless they all have the same attribute. It would work if all tables had BID, but the second join is trying to join AID. Which wont work. They all have to have BID.
Based on your comments
i would like to get is just one asset per blog post (top one ordered
by Priority)
You can change your query as following. I suggest changing the join with dbo.tblAssetLink to filtered one, which contains only one (highest priority) link for every blog.
SELECT dbo.tblBlog.BID,
dbo.tblBlog.DateAdded,
dbo.tblBlog.PMonthName,
dbo.tblBlog.PDay,
dbo.tblBlog.Header,
dbo.tblBlog.AddedBy,
dbo.tblBlog.PContent,
dbo.tblBlog.Category,
dbo.tblBlog.Deleted,
dbo.tblBlog.Intro,
dbo.tblBlog.Tags,
dbo.tblAssets.Name,
dbo.tblAssets.Description,
dbo.tblAssets.Location,
dbo.tblAssets.Deleted AS Expr1,
dbo.tblAssetLink.Priority
FROM dbo.tblBlog
LEFT OUTER JOIN
(SELECT BID, AID,
ROW_NUMBER() OVER (PARTITION BY BID ORDER BY [Priority] DESC) as N
FROM dbo.tblAssetLink) AS filteredAssetLink
ON dbo.tblBlog.BID = filteredAssetLink.BID
LEFT OUTER JOIN dbo.tblAssets
ON filteredAssetLink.AID = dbo.tblAssets.AID
WHERE dbo.tblBlog.Deleted = 'False' AND filteredAssetLink.N = 1
ORDER BY tblBlog.DateAdded DESC