T SQL Chain join 4 tables - sql

Here is the scenario:
I have tables:
Articles (articleId, userId, title, datePosted)
ArticleTranslations (languageId, articleId, title) (not so important for this case, but I am showing anyway)
ArticleSections (articleSectionId, articleId, sectionId)
sections (sectionId, content, ...)
sectionsAdditionalInfo (sectionId, isApproved)
What I am doing is selecting some articles from articles by userId in a way:
SELECT article.articleId, article.userId, ArticleTranslations.title, article.datePosted
FROM Articles
LEFT OUTER JOIN ArticleTranslations ON Article.articleId= ArticlesTranslations.articleId AND ArticlesTranslations.languageId=#languageId
WHERE Articloes.userId=#userId
ORDER BY
CASE WHEN #sortDirection = 'DD' THEN datePosted END DESC, -- by date posted
CASE WHEN #sortDirection = 'DA' THEN datePosted END,
CASE WHEN #sortDirection = 'ND' THEN title END DESC, -- sort by name
CASE WHEN #sortDirection = 'NA' THEN title END,
CASE WHEN #sortDirection = 'SD' THEN ArticleTranslations.isApproved END DESC, -- is article aproved?
CASE WHEN #sortDirection = 'SA' THEN ArticleTranslations.isApproved END,
CASE WHEN #sortDirection = 'ID' THEN areAllSectionsApproved END DESC, -- sort by information if sections are all approved - within the article?
CASE WHEN #sortDirection = 'IA' THEN areAllSectionsApproved END
Please bare in mind I left out some of the info in order for my question to be more understandable.
Now, what I would like to do is select another attribute (for each article returned in SQL above): areAllArticleSectionsApproved
I have assembled SQL separately, but I would like this to be returned for every row:
SELECT CASE WHEN COUNT(sectionsAdditionalInfo.sectionId) > 0 THEN 0 ELSE 1 END AS areAllSectionsApproved
FROM ArticleSections
LEFT OUTER JOIN sectionsAdditionalInfo ON ArticleSections.sectionId = sectionsAdditionalInfo.sectionId
WHERE articleId=#articleId AND sectionsAdditionalInfo.isApproved=0
I have tried nesting this SQL, in a way:
SELECT (outer SQL) .....
a.*(
nested SQL - second one I posted here
) as a
but it didn't work at all.
I am using SQL server 2008.
Any hint on how to solve this would be greatly appreciated ;)

Without fully understanding your data and your desired results, something like this should work using your above query and joining on your second query as a subquery:
SELECT article.articleId,
article.userId,
ArticleTranslations.title,
article.datePosted,
t.areAllSectionsApproved
FROM Articles
LEFT OUTER JOIN ArticleTranslations
ON Article.articleId= ArticlesTranslations.articleId
AND ArticlesTranslations.languageId=#languageId
LEFT JOIN (
SELECT
articleId,
CASE
WHEN COUNT(sectionsAdditionalInfo.sectionId) > 0
THEN 0
ELSE 1
END AS areAllSectionsApproved
FROM ArticleSections
LEFT OUTER JOIN sectionsAdditionalInfo
ON ArticleSections.sectionId = sectionsAdditionalInfo.sectionId
WHERE sectionsAdditionalInfo.isApproved=0
GROUP BY articleId
) t ON articles.articleId = t.articleId
WHERE Articloes.userId=#userId
ORDER BY
CASE WHEN #sortDirection = 'DD' THEN datePosted END DESC, -- by date posted
CASE WHEN #sortDirection = 'DA' THEN datePosted END,
CASE WHEN #sortDirection = 'ND' THEN title END DESC, -- sort by name
CASE WHEN #sortDirection = 'NA' THEN title END,
CASE WHEN #sortDirection = 'SD' THEN ArticleTranslations.isApproved END DESC, -- is article aproved?
CASE WHEN #sortDirection = 'SA' THEN ArticleTranslations.isApproved END,
CASE WHEN #sortDirection = 'ID' THEN areAllSectionsApproved END DESC, -- sort by information if sections are all approved - within the article?
CASE WHEN #sortDirection = 'IA' THEN areAllSectionsApproved END
Good luck.

Related

How to sort data in stored procedure with column positions of select statement with CASE

This is not working
ORDER BY
CASE
WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection = 'D'
THEN 10
END DESC,
CASE
WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection != 'D'
THEN 10
END
Where this one is working
ORDER BY 10 DESC
As per documentation,
ORDER BY order_by_expression
order_by_expression Specifies a column or expression on which to sort
the query result set. A sort column can be specified as a name or
column alias, or a nonnegative integer representing the position of
the column in the select list.
Source: SELECT - ORDER BY Clause (Transact-SQL)
You are specifying an expression, hence the SQL Server does not sort by value in column #10. Instead it sorts your rows by a constant value '10', which results in no sort being performed.
Suggested solution
Move all complex columns into a CROSS APPLY sub-query and add another CROSS APPLY with a sorting column:
SELECT F.Id
,cols.Favourite
,F.Agent
,F.Name
,cols.DatePublished
,UF.ToolTip
,F.CreationDate
FROM MyTable F
INNER JOIN MyTable2 UF
ON f.Id = UF.Id
CROSS APPLY (
SELECT (CASE WHEN UFF.[Id] IS NULL THEN CONVERT(BIT, 0) ELSE CONVERT(BIT, 1) END) AS Favourite
,CONVERT(Datetime, F.[Date] , 103) AS DatePublished
) cols
CROSS APPLY (
SELECT -- Make sure to correctly cast all numeric and date values to text
CASE WHEN #OrderBy = 'EndDateInDays' THEN CONVERT(VARCHAR(100), F.[EndDateDate], 126)
WHEN #OrderBy = 'Name' THEN F.Name
WHEN #OrderBy = 'DatePublished' THEN cols.DatePublished
ELSE CONVERT(VARCHAR(100), F.Id) -- This is default sort
END AS [SortCol]
) sort
ORDER BY
CASE WHEN #OrderByDirection = 'D' THEN sort.[SortCol] END DESC
,CASE WHEN #OrderByDirection != 'D' THEN sort.[SortCol] END
;
You can use the column alias. Let's say it is EndDateInDays:
ORDER BY (CASE WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection = 'D'
THEN EndDateInDays
END) DESC,
(CASE WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection <> 'D'
THEN EndDateInDays
END)
If EndDateInDays is a number (as suggested by the name), you could do:
ORDER BY (CASE WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection = 'D'
THEN - EndDateInDays
WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection <> 'D'
THEN EndDateInDays
END)
Also, be careful if you start combining multiple columns. It is better to have a separate CASE expression for each column to prevent inadvertent type mismatching.

Group By Operator Not Behaving as Expected

I have this query:
SELECT groupname,
Result = CASE
WHEN ( thd_requesttype_dca_oms_form IS NULL
OR thd_requesttype_dca_oms_form = '' ) THEN
thd_requesttypeidmform
ELSE thd_requesttype_dca_oms_form
END
FROM zendeskticketexport
WHERE (groupname = 'DC Maintenance')
AND thd_requesttype_dca_oms_form = 'attribute_update_requests__discontinue___obsolete_request'
GROUP BY groupname,
thd_requesttype_dca_oms_form,
thd_requesttypeidmform
ORDER BY groupname
The result I am receiving:
groupname Result
DC Maintenance attribute_update_requests__discontinue___obsolete_request
DC Maintenance attribute_update_requests__discontinue___obsolete_request
DC Maintenance attribute_update_requests__discontinue___obsolete_request
What's throwing me off is the result; I believe the group by operator should group identical records together, but something with the group by operator in conjuction with the case operator is causing these records not to group. In testing the two cases, I see the following query is returning 0 records:
select * from ZendeskTicketExport
where groupName = 'DC Maintenance' and thd_requesttypeidmform = 'attribute_update_requests__discontinue___obsolete_request'
In my mind this would indicate that all of the records should group together, since the case operator is only returning values for the thd_requesttype_dca_oms_form field. Thanks in advance.
You're grouping by a third column. SQL Server will create your groups, even if that column itself isn't in the SELECT.
Try this instead:
SELECT groupname,
CASE
WHEN (thd_requesttype_dca_oms_form IS NULL OR
thd_requesttype_dca_oms_form = '' ) THEN thd_requesttypeidmform
ELSE thd_requesttype_dca_oms_form
END
FROM zendeskticketexport
WHERE
groupname = 'DC Maintenance' AND
thd_requesttype_dca_oms_form = 'attribute_update_requests__discontinue___obsolete_request'
GROUP BY groupname,
thd_requesttype_dca_oms_form,
CASE
WHEN (thd_requesttype_dca_oms_form IS NULL OR
thd_requesttype_dca_oms_form = '' ) THEN thd_requesttypeidmform
ELSE thd_requesttype_dca_oms_form
END
ORDER BY groupname

How to make order by clause dynamic

I am using SQL Server 2008, I want sorted data based on input column name and sort order (asc/ desc).How to make below query dynamic?
DECLARE #iColumnName VARCHAR(24);
DECLARE #iSortOrder VARCHAR(10);
SET #iColumnName = 'ReceiptLocation'; -- ReceiptLocation/DeliverLocation/NominationNbr
SET #iSortOrder = 'DESC'; -- DESC / ASC
SELECT sum(NominationNbr)
,sum(ReceiptLocation)
,sum(DeliverLocation)
FROM tables
GROUP BY NominationNbr
,ReceiptLocation
,DeliverLocation
ORDER BY CASE #iColumnName
WHEN 'ReceiptLocation'
THEN ReceiptLocation
WHEN 'DeliverLocation'
THEN DeliverLocation
ELSE NominationNbr
END
CASE #iSortOrder
WHEN 'DESC'
THEN DESC
ELSE ASC
END
You need to combine the two. I would suggest this rather clunky code:
ORDER BY (CASE WHEN #iColumnName = 'ReceiptLocation' AND #iSortOrder = 'DESC'
THEN ReceiptLocation
END) DESC,
(CASE WHEN #iColumnName = 'ReceiptLocation'
THEN ReceiptLocation
END) ASC,
(CASE WHEN #iColumnName = 'DeliverLocation' AND #iSortOrder = 'DESC'
THEN DeliverLocation
END) DESC,
(CASE WHEN #iColumnName = 'DeliverLocation'
THEN DeliverLocation
END) ASC,
(CASE WHEN #iSortOrder = 'DESC'
THEN NominationNbr
END) DESC,
NominationNbr ASC
Each CASE statement is a separate order key. However, the values are NULL if they do not match, so the key doesn't do anything with no match.
You can also implement this using dynamic SQL. That can be more effective if you have a simple query and indexes that can be used for the ORDER BY.

Unable to ORDER BY on Column Alias when using CASE

I have a column that will show 'active' if the 'Expiration Date' in the empTable is < Current Date, and will show 'inactive' otherwise, then I want to sort that column so that all 'active' employees will be at the top.
CREATE PROCEDURE SOME_SP
#SortBy VARCHAR(10)
AS
SELECT emp.empname,
CASE WHEN (emp.expiration_date < CURRENT_TIMESTAMP) THEN 'Active' ELSE 'InActive' END AS Emp_Status, DeptName
FROM empTable emp, Dept dpt
WHERE emp.ID = dpt.ID
CASE #sortBy WHEN 'NAME' THEN emp.empName END,
CASE #sortBy WHEN 'STATUS' THEN Emp_Status END
If the user enter 'NAME', then the SP will sort by emp.empName, which works fine, but not the STATUS
I get an error saying that Invalid column name 'Emp_Status'
What did I do wrong?
Edited: I'm so sorry, I realize this query works if it is in plain SQL. However, the fact is I'm doing it in the Stored Procedure where the user can specify which column to sort. I will post a more complete SP above.
Okay, here are some comments that I have.
1 - Please get away from old style joins. Use the INNER JOIN ON clause.
2 - There is no reason why an alias can not be used in the ORDER BY clause. Please see Itzik Ben-Gans posting on logical processing order. The SELECT arguments are processed way before the ORDER BY.
http://www.sql.co.il/books/insidetsql2008/Logical%20Query%20Processing%20Poster.pdf
3 - Last but not least, a simple example (adventureworks) that make everyone with a hire date less than 2004 as Active, everyone else is in-active. This will sort by the status column.
Good luck.
John
-- Sample database
Use AdventureWorks2012
GO
-- Sample select showing alias works fine in a order by clause.
SELECT [LoginID] as login_id,
CASE WHEN (e.HireDate < '20040101') THEN 'Active'
ELSE 'InActive' END AS emp_status
FROM [HumanResources].[Employee] as e
ORDER BY emp_status desc
GO
Since you changed your code above, here is a new answer to match. For a CASE statement on an ORDER BY you have to use the actual columns. For just a simple ORDER BY, the alias will work.
SO THE ANSWER is it ALL DEPENDS!!
Use AdventureWorks2012
GO
ALTER PROCEDURE usp_Sort_By_Column(#sort varchar(25))
AS
SELECT
[LoginID] as login_id,
CASE WHEN (e.HireDate < '20040101')
THEN 'Active' ELSE 'InActive' END AS emp_status
FROM
[HumanResources].[Employee] as e
ORDER BY
(CASE
WHEN #sort = 'ID' THEN [LoginID] ELSE
(CASE WHEN (e.HireDate < '20040101')
THEN 'Active' ELSE 'InActive' END)
END)
GO
usp_Sort_By_Column 'STATUS'
Link to ORDER BY - Books On Line ...
http://msdn.microsoft.com/en-us/library/ms188385.aspx
Best answer for your crazy query: Make a sort column that is dynamic using the variable. Just order by the first column. Cleanest answer.
Use AdventureWorks2012
GO
ALTER PROCEDURE usp_Sort_By_Column(#sort varchar(25))
AS
SELECT
(CASE
WHEN #sort = 'ID' THEN [LoginID] ELSE
(CASE WHEN (e.HireDate < '20040101')
THEN 'Active' ELSE 'InActive' END)
END) as Sort_Column,
[LoginID] as login_id,
CASE WHEN (e.HireDate < '20040101')
THEN 'Active' ELSE 'InActive' END AS emp_status
FROM
[HumanResources].[Employee] as e
ORDER BY
1
GO
usp_Sort_By_Column 'ID'

0 come last when sorting ascending

I am trying to select from one table a list of products ordered by price, year, name, and others....
The problem is that I must make zero values come last when sorting ascending.
My code is:
SELECT * FROM Product P
ORDER BY CASE WHEN #OrderBy='Date ASC' THEN Date END ASC,
CASE WHEN #OrderBy='Price ASC' THEN Price END ASC,
CASE WHEN #OrderBy='Title ASC' THEN Title END ASC,
CASE WHEN #OrderBy='' THEN Match END
This works but don't put the zero at the bottom of the list.
So, I tried to transform it (see next code), but it gave me the error Incorrect syntax near ','.
SELECT * FROM Product P
ORDER BY CASE WHEN #OrderBy='Price ASC' THEN
(case A.Price WHEN 0 THEN 1 ELSE 0 END,A.Price )
END ASC
I appreciate any help
You can do it by testing for price-ordering twice:
SELECT * FROM Product P
ORDER BY CASE WHEN #OrderBy='Date ASC' THEN Date END ASC,
CASE WHEN #OrderBy='Price ASC' THEN CASE WHEN Price = 0 THEN 1 ELSE 0 END ASC,
CASE WHEN #OrderBy='Price ASC' THEN Price END ASC,
CASE WHEN #OrderBy='Title ASC' THEN Title END ASC,
CASE WHEN #OrderBy='' THEN Match END
By the way, the implicit value of the case expression when #orderBy doesn't equal the string is null. When the sort column contains all nulls, it effectively disables sorting for that attribute.
I would suggest using a large dummy price:
ORDER BY CASE WHEN #OrderBy='Price ASC' THEN 99999999 ELSE A.Price END ASC
or if you DBMS supports NULLS LAST:
ORDER BY CASE WHEN #OrderBy='Price ASC' THEN NULLIF(A.Price,0) END ASC NULLS LAST
You can try with this syntax:
SELECT *,
CASE WHEN #OrderBy = 'Price ASC' AND Price = 0 THEN 1 ELSE 0 END AS OrderPriceZeroLast
FROM Product P
ORDER BY OrderPriceZeroLast,
CASE WHEN #OrderBy = 'Date ASC' THEN Date END ASC,
CASE WHEN #OrderBy = 'Price ASC' THEN Price END ASC,
CASE WHEN #OrderBy = 'Title ASC' THEN Title END ASC,
CASE WHEN #OrderBy = '' THEN Match END
I can't add comments yet. There is bug in your code
SELECT * FROM Product P
ORDER BY CASE WHEN #OrderBy='Price ASC' THEN
(case A.Price WHEN 0 THEN 1 ELSE 0 END,A.Price )
END ASC
Shoud be smth like
SELECT *
FROM Product P
ORDER BY
CASE
WHEN #OrderBy='Price ASC'
THEN
CASE A.Price
WHEN 0
THEN 1
ELSE 0
END
END,
A.Price
This may seem like a hack but you could create a new column on the result set on the fly. Like this:
SELECT *, [name of column that may contain zeroes] as foo WHERE /* rest of your code */
Then you could sort DESC on foo and ASC on the rest. Just remember to now show foo to the user. Also notice that yes, you'll get the same column in the result set twice. You also have to use a CASE to turn all non-zero values into 1 (or some other constant value).
Try this to sort 0 value to last, when there are 0,1,2,... values are in field.
It will bring 1, 2 ,... and 0 to last order.
select * from Product
order by
case
when OrderBy = 0
then -1
else 0
end,
OrderBy desc
-Chirag