Set alias for column values - sql

Is it possible to Set Alias for Column Values as we are set for column header in sql server.
Or if there is any other way to convert my column values to readable format for clients.
I have the following System generated values:
BILL_DETAILS
BILLING_MENU
ComplaintNumberInput
CUSTOMER_ACCOUNT_NUMBER_INPUT
DEFAULTER
FAULTS_SHUTDOWN_MENU
KUNDA_CONNECTION
LOAD_SHEDDING_MENU
LOAD_SHEDDING_SCHEDULED
loadSheddingScheduleReplayer
loadSheddingStatus
loadSheddingStatusReplayer
MENU_CONTEXT_EVAL
POWER_COMPLAINTS_MENU
repaetComplaintStatus
Is it possible to change them in the following:
BILL DETAILS
BILLING MENU
COMPLAINT NUMBER INPUT
CUSTOMER ACCOUNT NUMBER INPUT
DEFAULTER
FAULTS SHUTDOWN MENU
KUNDA CONNECTION
LOAD SHEDDING MENU
LOAD SHEDDING SCHEDULED
LOAD SHEDDING SCHEDULE REPLAYER
LOAD SHEDDING STATUS
LOAD SHEDDING STATUS REPLAYER
MENU CONTEXT EVAL
POWER COMPLAINTS MENU
REPEAT COMPLAINT STATUS

In sql, an Alias is a different name for a database object. Values does not fall under this category so it's impossible to alias them. You can, however, format the output of your query, though formatting is usually best to do in the presentation layer and not in the data layer.
Having said that, there is a t-sql solution for your question:
SELECT REPLACE(ColumnName, '_', ' ') As ColumnName
FROM TableName
This will convert all underlines to spaces.
To handle the other format you can thank Jeff Moden for solving that problem as well (see this link).
SELECT COALESCE(STUFF(ColumnName, NULLIF(patindex('%[a-z][A-Z]%', ColumnName COLLATE Latin1_General_BIN), 0) + 1, 0, ' '), Col) AS ColumnName
FROM TableName
So combining the 2 solutions your final sql should be something like this:
SELECT REPLACE(COALESCE(STUFF(ColumnName, NULLIF(patindex('%[a-z][A-Z]%', ColumnName COLLATE Latin1_General_BIN), 0) + 1, 0, ' '), ColumnName), '_', ' ') AS ColumnName
FROM TableName
This way you can handle these 2 formats in pure t-sql without having to change your query whenever a new value is added to the table.
Here is a test case with the values you posted:
DECLARE #t TABLE (Col VARCHAR(40))
INSERT INTO #t VALUES
('BILL_DETAILS'),
('BILLING_MENU'),
('ComplaintNumberInput'),
('CUSTOMER_ACCOUNT_NUMBER_INPUT'),
('DEFAULTER'),
('FAULTS_SHUTDOWN_MENU'),
('KUNDA_CONNECTION'),
('LOAD_SHEDDING_MENU'),
('LOAD_SHEDDING_SCHEDULED'),
('loadSheddingScheduleReplayer'),
('loadSheddingStatus'),
('loadSheddingStatusReplayer'),
('MENU_CONTEXT_EVAL'),
('POWER_COMPLAINTS_MENU'),
('repaetComplaintStatus')
SELECT Col
,UPPER(REPLACE(COALESCE(STUFF(col, NULLIF(patindex('%[a-z][A-Z]%', Col COLLATE Latin1_General_BIN), 0) + 1, 0, ' '), Col), '_', ' ')) AS NewCol
FROM #t
Results:
Col NewCol
BILL_DETAILS BILL DETAILS
BILLING_MENU BILLING MENU
ComplaintNumberInput COMPLAINT NUMBERINPUT
CUSTOMER_ACCOUNT_NUMBER_INPUT CUSTOMER ACCOUNT NUMBER INPUT
DEFAULTER DEFAULTER
FAULTS_SHUTDOWN_MENU FAULTS SHUTDOWN MENU
KUNDA_CONNECTION KUNDA CONNECTION
LOAD_SHEDDING_MENU LOAD SHEDDING MENU
LOAD_SHEDDING_SCHEDULED LOAD SHEDDING SCHEDULED
loadSheddingScheduleReplayer LOAD SHEDDINGSCHEDULEREPLAYER
loadSheddingStatus LOAD SHEDDINGSTATUS
loadSheddingStatusReplayer LOAD SHEDDINGSTATUSREPLAYER
MENU_CONTEXT_EVAL MENU CONTEXT EVAL
POWER_COMPLAINTS_MENU POWER COMPLAINTS MENU
repaetComplaintStatus REPAET COMPLAINTSTATUS

Use case statements for each value, like:
case old_column_name
when 'LOAD_SHEDDING_MENU'
then 'LOAD SHEDDING MENU'
when 'loadSheddingScheduleReplayer'
then 'LOAD SHEDDING SCHEDULE REPLAYER'
when ...........
then ...........
end as column_name

Related

How Do I Modify First Digit of Attribute in XML with SQL?

This is the section of my xml I am trying to modify:
<ORDER ORDER_NAME="10009999"
ORDER_NAME is an attribute.
This is what I have come up with so far and I think it's close, but slightly off.
update table_name set txn_message.modify('replace value of (/ORDER/#ORDER_NAME)[.=1000][1] with "2000"') , txn_status = 1
I want to replace 10009999 with 20009999 (really just something else to make it different so data can be reused, adding a additional character is also fine).
One way is
update t
set txn_message.modify('replace value of (/ORDER/#ORDER_NAME)[1] with concat("2", sql:column("vr"))')
from table_name t
cross apply (
select left(t.txn_message.value('(/ORDER/#ORDER_NAME)[1]','varchar(20)'), 1) vl
, substring (t.txn_message.value('(/ORDER/#ORDER_NAME)[1]','varchar(20)'), 2, 8000) vr
) v
where vl = '1';

OPENJSON - modify statement to ignore first part of the string

We receive auto-generated emails from an application, and we export those to our database as they arrive at the Inbox. The table is called dbo.MailArchive.
Up until recently, the body of the email has always looked like this...
Status: Completed
Successful actions count: 250
Page load count: 250
...except with different numbers and statuses. Note that there is a carriage return on the blank line after Page load count.
The entirety of this data gets written to a field called Mail_Body - then we run the following statement using OPENJSON to parse those lines into their own columns in the record:
DECLARE #PI varchar(7) = '%[^' + CHAR(13) + CHAR(10) + ']%';
SELECT j.Status,
j.Successful_Actions_Count,
j.Page_Load_Count
FROM dbo.MailArchive m
CROSS APPLY(VALUES(REVERSE(m.Mail_Body),PATINDEX(#PI,REVERSE(m.Mail_Body)))) PI(SY,I)
CROSS APPLY(VALUES(REVERSE(STUFF(PI.SY,1,PI.I,''))))S(FixedString)
CROSS APPLY OPENJSON (CONCAT('{"', REPLACE(REPLACE(S.FixedString, ': ', '":"'), CHAR(13) + CHAR(10), '","'), '"}'))
WITH (Status varchar(100) '$.Status',
Successful_Actions_Count int '$."Successful actions count"',
Page_Load_Count int '$."Page load count"') j;
Beginning today, there are certain emails where the body of the email looks like this:
Agent did not meet defined success criteria on this run.
Status: Completed
Successful actions count: 250
Page load count: 250
To clarify, that's one new line at the top, a carriage return at the end of that line, and a carriage return on the blank line between the new line and the Status line. At this time, there is no consistent way to predict which emails will come in with this new line, and which ones won't.
How can I modify our OPENJSON statement to say, If this first line exists in the body, skip/ignore it and parse lines 3 through 5, else just do exactly what I have above? Or perhaps even better to future-proof it, always ignore everything before the word Status?
Since your data has new leading and trailing rows, I think a simple aggregation in concert with a string_split() and a CROSS APPLY would be more effective than my previous XML answer and the current JSON approach
Example or dbFiddle
Select A.ID
,Status = stuff(Pos1,1,charindex(':',Pos1),'')
,Action = try_convert(int,stuff(Pos2,1,charindex(':',Pos2),''))
,PageCnt = try_convert(int,stuff(Pos3,1,charindex(':',Pos3),''))
From YourTable A
Cross Apply (
Select [Pos1] = max(case when Value like 'Status:%' then value end)
,[Pos2] = max(case when Value like '%actions count:%' then value end)
,[Pos3] = max(case when Value like 'Page load count:%' then value end)
From string_split(SomeCol,char(10))
) B
Returns
ID Status Action PageCnt
1 Completed 250 250
Note: Use an OUTER APPLY if you want to see NULLs

Azure Stream analytics default field values for missing fields

I have some json values coming in from an IOT datasource to stream analytics. They want to change the json in a later version to have extra fields but older versions will not have these fields. Is there a way I can detect the field is missing and set up a default value for it before it gets to the output? for example they would like to add an e.OSversion which if it did not exist would default to "unknown". The output is a sql database as it happens.
WITH MetricsData AS
(
SELECT * FROM [MetricsData]
PARTITION BY LID
WHERE RecordType='UseList'
)
SELECT
e.LID as LID
,e.EventEnqueuedUtcTime AS SubmitDate
,CAST (e.UsedDate as DateTime) AS UsedDate
,e.Version as Version
,caUsedList.ArrayValue.Module AS Module
,caUsedList.ArrayValue.UsageCount AS UsedCount
INTO
[ModuleUseOutput]
FROM
Usagedata as e
CROSS APPLY getElements (e.UsedList) as caUsedList
Please use case..when.. operator.
Example:
select j.id, case when j.version is null then 'unknown' else j.version end as version
from jsoninput as j
Output:
Or you could just set the default value in the sql database column directly.

Comparing 2 Columns until the 1st "."

I am new to SQL programming and I am trying to figure out how to get a report to show a mismatch in System Names & DNS Names. Both of the columns are in a table called nodes.
System Name router-1-dc and the DNS would be router-1-dc.domain I am trying to find Nodes that don't match to the "." prior to the domain example for this would be
System Name "router-1-datacenter" and DNS Name "router-1-dc.domain" I would want this example to show on the report page.
The tricky part is that some of the system names have the ".domain" and some don't.
Here is the SQL Query I built however it does not appear to be working as I need it too.
SELECT N. NodeID, N.Caption, N.SysName, N.DNS, N.IP_Address, N.Device_Type
FROM (
SELECT Nodes.NodeID, Nodes.Caption, Nodes.SysName, Nodes.DNS, Nodes.Device_Type, Nodes.IP_Address
FROM Nodes
WHERE CHARINDEX('.',Nodes.SysName)>0 AND CHARINDEX('.',Nodes.DNS)>0
) N
WHERE SUBSTRING(N.SysName, 1, CHARINDEX('.',N.SysName)-1) <> SUBSTRING(N.DNS, 1, CHARINDEX('.',N.DNS)-1)
AND N.Device_Type = 'UPS'
ORDER BY 5 ASC, 2 ASC
Thanks in advance for the help
Try this, or something like it (I've no data to test it against):
SELECT N.NodeID, N.Caption, N.SysName, N.DNS, N.IP_Address, N.Device_Type
from Nodes N
where left(n.sysname, charindex('.', n.sysname + '.') - 1 )
<> left(n.dns, charindex('.', n.dns + '.') - 1)
order by N.IP_Address, N.Caption
The trick is to add a "." to the end of each string for evaluation purposes. If there already is a period in the string, this has no effect, otherwist you get the whole string.

SQL Performance issue when using CASE

I have a SP that returns quite a lot of data every second and is shown in a grid. I'm now trying to reduce bandwidth and thinking of returning only columns currently shown in my grid.
This is of course simplified and minimized but basically what I had was the following SP:
SELECT
[Animals].[AnimalID] AS [AnimalID],
[Animals].[name] AS [AnimalName],
[Foods].[DisplayName] AS [Food],
[Animals].[Age] AS [AnimalAge],
[Animals].[AmountOfFood] AS [AmountOfFood]
What I’m currently trying is to pass a TVP of the names of the fields (#fields) currently shown on the grid and returning only required fields as such:
SELECT
[Animals].[AnimalID] AS [AnimalID],
[Animals].[name] AS [AnimalName],
CASE
WHEN ('Food' in (select * from #fields))
THEN [Foods].[DisplayName]
END AS [Food],
CASE
WHEN ('AnimalAge' in (select * from #fields))
THEN [Animals].[Age]
END AS [AnimalAge],
CASE
WHEN ('AmountOfFood' in (select * from #fields))
THEN [Animals].[AmountOfFood]
END AS [AmountOfFood]
The problem I'm facing is that (as could be expected) my SP went from taking ~200 ms to taking ~1 sec
Is there any way to maybe rewrite this so that it doesn’t kill us?
My kingdom for a foreach!!!
In SQL Server, you can also do this with dynamic SQL. Something like:
declare #sql nvarchar(max);
select #sql = (select ', '+
(case when FieldName = 'Food' then 'Foods.DisplayName'
when FieldName = 'AnimalAge' then 'Animals.Age'
. . .
end)
from #fields
for xml path ('')
);
select #sql = 'select [Animals].[AnimalID] AS [AnimalID], [Animals].[name] AS [AnimalName]'+#sql+RESTOFQUERY;
exec(#sql);
I'd try to convert the stored procedure into Table-Valued function, and make your grid select only required columns from it.
So your function would still select
SELECT
[Animals].[AnimalID] AS [AnimalID],
[Animals].[name] AS [AnimalName],
[Foods].[DisplayName] AS [Food],
[Animals].[Age] AS [AnimalAge],
[Animals].[AmountOfFood] AS [AmountOfFood]
If the client only selected for example select * AnimalID, Age from myfunction(..), only these columns would be transferred to the client.