SQL Custom Sorting Bandwidth Data - sql

Beloved SO Cronies,
I'm trying to custom sort bandwidth data using ORDER BY or any performance-focused solution likely involving a temp table. I've scoured SO and Google and have only turned up parts of functions that I can use, so I've arrived at posting here as a final stop.
Data (example)
VALUE
---------
10 Kbps
5 Kbps
1 Mbps
10 Mbps
100 Mbps
10 Gbps
1 Gbps
SQL fiddle with the below. Can you hear it playing in the background?
Bandwidth Sorting Start (SQL Fiddle)
select * from Bandwidth
order by (
case
when Value like '%kbps%' then 1
when Value like '%mbps%' then 2
when Value like '%gbps%' then 3
else 4
end)
My thinking is splitting the string Value into a parameter and running a case on the metric type (e.g. Kbps, Mbps) then applying a multiplier to the parameter based on that and presenting that in a temp table that I can sort and return on an int-based sort without showing the column in the results!
Thanks in advance. I tried to post on DBA StackExchange but existing work location presently blocks the login creation there.

Just use a delimiter to separate the numbers and convert them to integer
order by
(
case
when Value like '%Kbps%' then 1
when Value like '%Mbps%' then 2
when Value like '%Gbps%' then 3
else 4
end) ,
CONVERT(INT,SUBSTRING(Value, 0, CHARINDEX(' ', Value)))
FIDDLE

Related

Finding gaps in server data using presto

I have the data for requests sent to a server with the API endpoint name and the epoch at which the request was sent. There are many API endpoints (in thousands). There was an issue due to which the requests didn't come into the server. I want to find out the list of APIs whose data didn't come in, i.e., I want to find out the gaps in this server data.
I followed some examples in https://blog.jooq.org/how-to-find-the-longest-consecutive-series-of-events-in-sql/. But this uses window functions and works well for consecutive dates for a single group but doesn't extend to multiple groups of epochs since they might not be consecutive. I want to extend this to my use case, where there are multiple APIs, each with its own epochs and gaps. How can I do it in Presto?
Example schema in the table
endpointid (string)
serverepoch (integer)
Example Data
endpointid1, 123
endpointid2, 123
endpointid1, 234
endpointid2, 567
From this data, say I want to find all gaps of 300 seconds or more then I get
endpointid2 123
endpointid2 567
You could use the lead and lag functions as the following:
with next_prev_serverepoch_gaps as
(
select *,
case
when lead(serverepoch, 1, serverepoch) over (partition by endpointid order by serverepoch) - serverepoch >= 300
or serverepoch - lag(serverepoch, 1, serverepoch) over (partition by endpointid order by serverepoch) >= 300
then 1 else 0
end as gap_flag
from table_name
)
select endpointid, serverepoch
from next_prev_serverepoch_gaps
where gap_flag = 1
order by endpointid, serverepoch

How to check changes in column values?

I need to try to check some device IDs for work. These are values (15 characters, random string of numbers+letters) that mostly remain constant for users. However, every now and then these deviceIDs will change. And I'm trying to detect when they do change. Is there a way to write this kind of a dynamic query with SQL? Say, perhaps with a CASE statement?
user
device
date
1
23127dssds1272d
10-11
1
23127dssds1272d
10-11
1
23127dssds1272d
10-12
1
23127dssds1272d
10-12
1
04623jqdnq3000x
10-12
Count distinct device by id having count > 1?
Consider below approach
select *
from your_table
where true
qualify device != lag(device, 1, '') over(partition by user order by date)
if applied to sample data in your question - output is
As you can see here - at 10-11 first 'change, assignment' happened for user=1 ; and then on 10-12 he device changed

How to replace 0 and 1 in SQL Server 2012

I have a rugby database + player table. In the player table I have performance and I want to represent the performance as
0 = low
1 = medium
2 = high
I don't know what datatype the column should be. And what is the formula or function to do that?
Please help
You can define your column like this:
performance tinyint not null check (performance in (0, 1, 2))
tinyint takes only 1 byte for a value and values can range from 0 to 255.
If you store the values as 1 - Low, 2 - Medium, 3 - High and are using SQL server 2012+, then you can simply use CHOOSE function to convert the value to text when select like this:
select choose(performance,'Low','Medium','High')
. . .
If you really want to store as 0,1,2, use :
select choose(performance+1,'Low','Medium','High')
. . .
If you are using a lower version of SQL server, you can use CASE like this:
case performance
when 0 then 'Low'
when 1 then 'Medium'
when 2 then 'High'
end
1- column datatype should b int.
2- where you send the date check the performance first like:-
if(performance = low)
perVar = 0
send into database
There are a number of ways you can handle this. One way would be to represent the performance using an int column, which would take on values 0, 1, 2, .... To get the labels for those peformances, you could create a separate table which would map those numbers to descriptive strings, e.g.
id | text
0 | low
1 | medium
2 | high
You would then join to this table whenever you needed the full text description. Note that this is probably the only option which will scale as the number of performance types starts to get large.
If you don't want a separate table, you could also use a CASE expression to generate labels when querying, e.g.
CASE WHEN id = 0 THEN 'low'
WHEN id = 1 THEN 'medium'
WHEN id = 1 THEN 'high'
END
I would use a TINYINT datatype in the performance table to conserve space, then use a FOREIGN KEY CONSTRAINT from a second table which holds the descriptions. The constraint would force the entry of 0, 1, 2 in the performance table while providing a normalized solution that could grow to include additional perforamnce metrics.

Access SQL - Add Row Number to Query Result for a Multi-table Join

What I am trying to do is fairly simple. I just want to add a row number to a query. Since this is in Access is a bit more difficult than other SQL, but under normal circumstances is still doable using solutions such as DCount or Select Count(*), example here: How to show row number in Access query like ROW_NUMBER in SQL or Access SQL how to make an increment in SELECT query
My Issue
My issue is I'm trying to add this counter to a multi-join query that orders by fields from numerous tables.
Troubleshooting
My code is a bit ridiculous (19 fields, seven of which are long expressions, from 9 different joined tables, and ordered by fields from 5 of those tables). To make things simple, I have an simplified example query below:
Example Query
SELECT DCount("*","Requests_T","[Requests_T].[RequestID]<=" & [Requests_T].[RequestID]) AS counter, Requests_T.RequestHardDeadline AS Deadline, Requests_T.RequestOverridePriority AS Priority, Requests_T.RequestUserGroup AS [User Group], Requests_T.RequestNbrUsers AS [Nbr of Users], Requests_T.RequestSubmissionDate AS [Submitted on], Requests_T.RequestID
FROM (((((((Requests_T
INNER JOIN ENUM_UserGroups_T ON ENUM_UserGroups_T.UserGroups = Requests_T.RequestUserGroup)
INNER JOIN ENUM_RequestNbrUsers_T ON ENUM_RequestNbrUsers_T.NbrUsers = Requests_T.RequestNbrUsers)
INNER JOIN ENUM_RequestPriority_T ON ENUM_RequestPriority_T.Priority = Requests_T.RequestOverridePriority)
ORDER BY Requests_T.RequestHardDeadline, ENUM_RequestPriority_T.DisplayOrder DESC , ENUM_UserGroups_T.DisplayOrder, ENUM_RequestNbrUsers_T.DisplayOrder DESC , Requests_T.RequestSubmissionDate;
If the code above is trying to select a field from a table not included, I apologize - just trust the field comes from somewhere (lol i.e. one of the other joins I excluded to simply the query). A great example of this is the .DisplayOrder fields used in the ORDER BY expression. These are fields from a table that simply determines the "priority" of an enum. Example: Requests_T.RequestOverridePriority displays to the user as an combobox option of "Low", "Med", "High". So in a table, I assign a numerical priority to these of "1", "2", and "3" to these options, respectively. Thus when ENUM_RequestPriority_T.DisplayOrder DESC is called in order by, all "High" priority requests will display above "Medium" and "Low". Same holds true for ENUM_UserGroups_T.DisplayOrder and ENUM_RequestNbrUsers_T.DisplayOrder.
I'd also prefer to NOT use DCOUNT due to efficiency, and rather do something like:
select count(*) from Requests_T where Requests_T.RequestID>=RequestID) as counter
Due to the "Order By" expression however, my 'counter' doesn't actually count my resulting rows sequentially since both of my examples are tied to the RequestID.
Example Results
Based on my actual query results, I've made an example result of the query above.
Counter Deadline Priority User_Group Nbr_of_Users Submitted_on RequestID
5 12/01/2016 High IT 2-4 01/01/2016 5
7 01/01/2017 Low IT 2-4 05/06/2016 8
10 Med IT 2-4 07/13/2016 11
15 Low IT 10+ 01/01/2016 16
8 Low IT 2-4 01/01/2016 9
2 Low IT 2-4 05/05/2016 2
The query is displaying my results in the proper order (those with the nearest deadline at the top, then those with the highest priority, then user group, then # of users, and finally, if all else is equal, it is sorted by submission date). However, my "Counter" values are completely wrong! The counter field should simply intriment +1 for each new row. Thus if displaying a single request on a form for a user, I could say
"You are number: Counter [associated to RequestID] in the
development queue."
Meanwhile my results:
Aren't sequential (notice the first four display sequentially, but then the final two rows don't)! Even though the final two rows are lower in priority than the records above them, they ended up with a lower Counter value simply because they had the lower RequestID.
They don't start at "1" and increment +1 for each new record.
Ideal Results
Thus my ideal result from above would be:
Counter Deadline Priority User_Group Nbr_of_Users Submitted_on RequestID
1 12/01/2016 High IT 2-4 01/01/2016 5
2 01/01/2017 Low IT 2-4 05/06/2016 8
3 Med IT 2-4 07/13/2016 11
4 Low IT 10+ 01/01/2016 16
5 Low IT 2-4 01/01/2016 9
6 Low IT 2-4 05/05/2016 2
I'm spoiled by PLSQL and other software where this would be automatic lol. This is driving me crazy! Any help would be greatly appreciated.
FYI - I'd prefer an SQL option over VBA if possible. VBA is very much welcomed and will definitely get an up vote and my huge thanks if it works, but I'd like to mark an SQL option as the answer.
Unfortuantely, MS Access doesn't have the very useful ROW_NUMBER() function like other clients do. So we are left to improvise.
Because your query is so complicated and MS Access does not support common table expressions, I recommend you follow a two step process. First, name that query you already wrote IntermediateQuery. Then, write a second query called FinalQuery that does the following:
SELECT i1.field_primarykey, i1.field2, ... , i1.field_x,
(SELECT field_primarykey FROM IntermediateQuery i2
WHERE t2.field_primarykey <= t1.field_primarykey) AS Counter
FROM IntermediateQuery i1
ORDER BY Counter
The unfortunate side effect of this is the more data your table returns, the longer it will take for the inline subquery to calculate. However, this is the only way you'll get your row numbers. It does depend on having a primary key in the table. In this particular case, it doesn't have to be an explicitly defined primary key, it just needs to be a field or combination of fields that is completely unique for each record.

How to change / convert values in Output that comes from SQL Server table

I have created a view in my SQL Server database which will give me number of columns.
One of the column heading is Priority and the values in this column are Low, Medium, High and Immediate.
When I execute this view, the result is returned perfectly like below. I want to change or assign values for these priorities. For example: instead of Low I should get 4, instead of Medium I should get 3, for High it should be 2 and for Immediate it should be 1.
What should I do to achieve this?
Ticket# Priority
123 Low
1254 Low
5478 Medium
4585 High
etc., etc.,
Use CASE:
Instead of Low I should get 4, instead of Medium I should get 3, for
High it should be 2 and for Immediate it should be 1
SELECT
[Ticket#],
[Priority] = CASE Priority
WHEN 'Low' THEN 4
WHEN 'Medium' THEN 3
WHEN 'High' THEN 2
WHEN 'Immediate' THEN 1
ELSE NULL
END
FROM table_name;
EDIT:
If you use dictionary table like in George Botros Solution you need to remember about:
1) Maintaining and storing dictionary table
2) Adding UNIUQE index to Priority.Name to avoid duplicates like:
Priority table
--------------------
Id | Name | Value
--------------------
1 | Low | 4
2 | Low | 4
...
3) Instead of INNER JOIN defensively you ought to use LEFT JOIN to get all results even if there is no corresponding value in dictionary table.
I have an alternative solution for your problem by creating a new Priority table (Id, Name, Value)
by joining to this table you will be able to select the value column
SELECT Ticket.*, Priority.Value
FROM Ticket INNER JOIN Priority
ON Priority.Name = Ticket.Priority
Note: although using the case keyword is the most straight forward solution for
this problem
this solution may be useful if you will need this priority value in many places at your system