Is ordering done by actual column or alias? - sql-server

Let's say I have a simple query like this:
select
subgroup,
subgroup + ' (' + cast(grade as varchar(1)) + 'G)' as grade,
count(*) as 'count'
From table_empl
where year(EnterDate) = year(getdate())
group by subgroup, grade
order by grade
It seems that order by grade is being ordered by the alias grade instead of the actual column grade; at least that's what the result shows.
Is this correct?
Since I can't change the columns that are included in the result, is the solution to add an alias to the actual column? Something like this?
select
grade as 'grade2',
subgroup,
subgroup + ' (' + cast(grade as varchar(1)) + 'G)' as grade,
count(*) as 'count'
From table_empl
where year(EnterDate) = year(getdate())
group by subgroup,grade
order by grade2

If you prefix the column name by its table name (or an alias given to the table in the FROM clause) in the ORDER BY clause, then it will use the column, not the expression computed in the SELECT clause and given the same name as the column.
So this should sort using the original grade column:
select
subgroup,
subgroup + ' (' + cast(grade as varchar(1)) + 'G)' as grade,
count(*) as 'count'
From table_empl
where year(EnterDate) = year(getdate())
group by subgroup, grade
order by table_empl.grade
Or:
select
subgroup,
subgroup + ' (' + cast(grade as varchar(1)) + 'G)' as grade,
count(*) as 'count'
From table_empl t
where year(EnterDate) = year(getdate())
group by subgroup, grade
order by t.grade

Instruction Order By runs after all instructions, even Select. And in this case it's correct to take alias instead actual column.
The clauses are processed in the following order:
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
You can use name(Alias) of table to specify table column

A very good question. Apparently, the official documentation does not provide a direct answer to it. However, one can imply the observed behaviour from the following fact: the difference between column alias and column is that the latter can be prefixed with its parent table name (alias), whereas the former cannot.
Since you didn't specify the table name in the ORDER BY clause, the column alias takes root.

Related

Add Alphabet column in select statement

I want to add alphabet column when we get write a select query
my query is: -
select empname, address from Employee table
I want to get data like
empname address alphabetcolumn
Pramod USA A
xyz USA B
You can use below approach.
in ASCII table A starts from 65. ROW_NUMBER starts from 1. Hence, I am summing row_number with 64 to get 65+.
select
empname,
address,
CHAR((ROW_NUMBER() OVER(ORDER BY empname ASC)) + 64) AS ALPHABET
from Employee
with two characters support you can use this approach
With r as
(
select
empname,
address,
CHAR((ROW_NUMBER() OVER(ORDER BY empname ASC)) + 64) AS rn
from Employee
)
select IIF(rn / 26 = 0, '', char(rn/26 + 64)) + char((rn -1) % 26 +65)
from r;
I get the idea that this isn't what the OP is after, but based on the limited information.
You can add a new column to your table by using:
ALTER TABLE Employee ADD alphabetcolumn char(1);

Adding number to text rows sql server

I have a columns named id and item and there are stored values like:
id item
1 value
2 value
3 value
etc. There are 192 rows. These values are in the system in different places and I need to find concrete value in database to change it to the name I need.
Is there some posibility to add number to rows, for example value_01, value_02 etc.
I know how to do it in C language, but have no idea how to do it in sql server.
Edited:
#lad2025
In system I have columns, that names are stored in database.
Names are same, for example:
In app Apple I have table name Apple
In app Storage I also have table name Apple
I need to change app Storage columns name Apple to different, but I dont know, which of databasa Apple values it is, so I want to add identifiers to string, to find the right one. So I need to update database values, to see them in system.
SQLFiddleDemo
DECLARE #pad INT = 3;
SELECT
[id],
[item] = [item] + '_' + RIGHT(REPLICATE('0', #pad) + CAST([id] AS NVARCHAR(10)), #pad)
FROM your_table;
This will produce result like:
value_001
value_010
value_192
EDIT:
After reading your comments it is not clear what you want to achieve, but check:
SqlFiddleDemo2
DECLARE #pad INT = 3;
;WITH cte AS
(
SELECT *,
[rn] = ROW_NUMBER() OVER (PARTITION BY item ORDER BY item)
FROM your_table
)
SELECT
[id],
[item] = [item] + '_' + RIGHT(REPLICATE('0', #pad) + CAST([rn] AS NVARCHAR(10)), #pad)
FROM cte
WHERE item = 'value'; /* You can comment it if needed */

SQL Server Equivalent of Oracle 'CONNECT BY PRIOR', and 'ORDER SIBLINGS BY'

I've got this Oracle code structure I'm trying to convert to SQL Server 2008 (Note: I have used generic names, enclosed column names and table names within square brackets '[]', and done some formatting to make the code more readable):
SELECT [col#1], [col#2], [col#3], ..., [col#n], [LEVEL]
FROM (SELECT [col#1], [col#2], [col#3], ..., [col#n]
FROM [TABLE_1]
WHERE ... )
CONNECT BY PRIOR [col#1] = [col#2]
START WITH [col#2] IS NULL
ORDER SIBLINGS BY [col#3]
What is the SQL Server equivalent template of the above code?
Specifically, I'm struggling with the LEVEL, and 'ORDER SIBLINGS BY' Oracle constructs.
Note:
The above "code" is the final output from a set of Oracle procedures. Basically, the 'WHERE' clause is built up dynamically and changes depending on various parameters passed. The code block starting with 'CONNECT BY PRIOR' is hard-coded.
For Reference:
The Simulation of CONNECT BY PRIOR of ORACLE in SQL SERVER article comes close, but it does not explain how to handle the 'LEVEL' and the 'ORDER SIBLINGS' constructs. ... And my mind is getting in a twist!
SELECT name
FROM emp
START WITH name = 'Joan'
CONNECT BY PRIOR empid = mgrid
equates to:
WITH n(empid, name) AS
(SELECT empid, name
FROM emp
WHERE name = 'Joan'
UNION ALL
SELECT nplus1.empid, nplus1.name
FROM emp as nplus1, n
WHERE n.empid = nplus1.mgrid)
SELECT name FROM n
If I have an initial template to work from, it will go a long way to helping me construct SQL Server stored procs to build up a correct T-SQL statement.
Assistance will be much appreciated.
Simulating the LEVEL column
The level column can easily be simulated by incrementing a counter in the recursive part:
WITH tree (empid, name, level) AS (
SELECT empid, name, 1 as level
FROM emp
WHERE name = 'Joan'
UNION ALL
SELECT child.empid, child.name, parent.level + 1
FROM emp as child
JOIN tree parent on parent.empid = child.mgrid
)
SELECT name
FROM tree;
Simulating order siblings by
Simulating the order siblings by is a bit more complicated. Assuming we have a column sort_order that defines the order of elements per parent (not the overall sort order - because then order siblings wouldn't be necessary) then we can create a column which gives us an overall sort order:
WITH tree (empid, name, level, sort_path) AS (
SELECT empid, name, 1 as level,
cast('/' + right('000000' + CONVERT(varchar, sort_order), 6) as varchar(max))
FROM emp
WHERE name = 'Joan'
UNION ALL
SELECT child.empid, child.name, parent.level + 1,
parent.sort_path + '/' + right('000000' + CONVERT(varchar, child.sort_order), 6)
FROM emp as child
JOIN tree parent on parent.empid = child.mgrid
)
SELECT *
FROM tree
order by sort_path;
The expression for the sort_path looks so complicated because SQL Server (at least the version you are using) does not have a simple function to format a number with leading zeros. In Postgres I would use an integer array so that the conversion to varchar isn't necessary - but that doesn't work in SQL Server either.
The option given by the user "a_horse_with_no_name" worked for me. I changed the code and applied it to a menu generator query and it worked the first time. Here is the code:
WITH tree(option_id,
option_description,
option_url,
option_icon,
option_level,
sort_path)
AS (
SELECT ppo.option_id,
ppo.option_description,
ppo.option_url,
ppo.option_icon,
1 AS option_level,
CAST('/' + RIGHT('00' + CONVERT(VARCHAR, ppo.option_index), 6) AS VARCHAR(MAX))
FROM security.options_table_name ppo
WHERE ppo.option_parent_id IS NULL
UNION ALL
SELECT co.option_id,
co.option_description,
co.option_url,
co.option_icon,
po.option_level + 1,
po.sort_path + '/' + RIGHT('00' + CONVERT(VARCHAR, co.option_index), 6)
FROM security.options_table_name co,
tree AS po
WHERE po.option_id = co.option_parent_id)
SELECT *
FROM tree
ORDER BY sort_path;
to get dates for last 10 days:
SELECT DISTINCT RecordDate = DATEADD(DAY,-number,CAST(GETDATE() AS DATE))
FROM master..[spt_values]
WHERE number BETWEEN 1 AND 10

MS SQL Server: Assign value to variable and reuse the var within the query

I am doing the follwoing e.g.:
SELECT name1, name2, left(name1,2) + '_' + left(name2,2), ID, ID + left(name1,2) + '_' + left(name2,2)
from person
So left(name1,2) + '_' + left(name2,2) is used more than one times. Is there any way I can do this better. I have queries where I have to call the same function chain 10 - 15 times.
Other example:
I some queries I need to get values with a sub-query
e.g.
Select name, (Select something from some_table where X=Y) , age from person
In some cases I do need the value returned from the sub-query for a different column also.
e.g.
Select name, (Select something from some_table where X=Y) , age,
left( (Select something from some_table where X=Y),2) as Test
from person
There must be an easier way...right?
You can use outer apply to re-use code, with something like this:
Select p.name, x.something, p.age, left(x.something,2) as Test
from person p
outer apply (
Select something from some_table s where s.X=p.Y
) x

Grouping based on pattern Sql

Say I have the following table name t1(deptName,courseName,fund) I want to get sum of fund of each courseName with its deptName.So far all I can do is group by courseName and sum(fund) to get sum of fund under each courseName but how can I also include deptName on each output row like deptName,CourseName sum(fund)?
Thanks in advance.
One possibility: concatenate deptName and courseName and group by that (that literally fulfills what you are asking).
SELECT deptName + '_' + courseName as Dept_Course, SUM(fund)
FROM t1
GROUP BY (deptName + '_' + courseName)
Or (thanks #giorgi):
SELECT deptName + '_' + courseName as Dept_Course, SUM(fund)
FROM t1
GROUP BY deptName,courseName
Usually, you can just do this, though:
SELECT deptName,courseName,SUM(fund)
FROM t1
GROUP BY deptName,courseName

Resources