SQL Sorting using Order by - sql

Can you all please help me with this?
Presently, I have this SELECT which returns data ordered by this way
SELECT DISTINCT gl.group_id,
gl.group_name,
gl.group_description,
gl.status_code,
gl.member_count,
(
SELECT grpp.group_name
FROM test_group_relationship grel
JOIN test_group grpp
ON grel.parent_group_id = grpp.group_id
WHERE grel.child_group_id = gl.group_id
) AS parent_group_name,
gl.group_name_key,
gl.group_description_key
FROM test_group gl
WHERE gl.group_org_id = '3909'
AND gl.group_name_key like '%' || 'GROUP' || '%'
ORDER BY
gl.group_name_key, CONVERT(gl.group_name, 'WE8EBCDIC500')
The output is below.I have tried indenting the columns to paste the data.
GROUP_NAME GROUP_NAME_KEY
Add Group Basic Flow ADD GROUP BASIC FLOW
Administrative Group ADMINISTRATIVE GROUP
Amy Group 33 AMY GROUP 33
Amy Test Group 1 AMY TEST GROUP 1
another add group test from matt ANOTHER ADD GROUP TEST FROM MATT
**My Question is in the FIELD GROUP_NAME--> how can i SORT DATA using ORDER BY
so that lowercase letters will be sorted before uppercase letters.
Expected output is :-
the value "another add group test from matt" has to come at the first place.This way
lowercase letters are sorted first and then UPPER CASE.
See also:
SQL ORDER BY Issue Continued
PLSQL ORDER BY Issue

Convert the type on the field to a collation that is case sensitive and order by it asc
In your order by add
Group_Name COLLATE Latin1_General_CS_AS Asc
assuming that your characters are in english; otherwise substitute french etc.

try:
ORDER BY UPPER (SUBSTR (GROUP_NAME, 1, 1)), SUBSTR (GROUP_NAME, 1, 1) DESC, UPPER(GROUP_NAME), GROUP_NAME DESC;

Just add BINARY to your ORDER BY.
ORDER BY BINARY gl.group_name_key
You may have to use DESC otherwise upper case will come first. But then that would also sort z-a.

I'm not an Oracle guy, but depending on your version of Oracle, I believe that there are some session variables that will determine this for you. You can try the following:
ALTER SESSION SET nls_comp=binary;
ALTER SESSION SET nls_sort=GENERIC_M_CI;

Related

Change duplicate value in a column

Can you please tell me what SQL query can I use to change duplicates in one column of my table?
I found these duplicates:
SELECT Model, count(*) FROM Devices GROUP BY model HAVING count(*) > 1;
I was looking for information on exactly how to change one of the duplicate values, but unfortunately I did not find a specific option for myself, and all the more information is all in abundance filled by deleting the duplicate value line, which I don't need. Not strong in SQL at all. I ask for help. Thank you so much.
You can easily use a Window Functions such as ROW_NUMBER() with partitioning option in order to group by Model column to eliminate the duplicates, and then pick the first rows(rn=1) returning from the subquery such as
WITH d AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY Model) AS rn
FROM Devices
)
SELECT ID, Model -- , and the other columns
FROM d
WHERE rn = 1
Demo
use exists as follows:
update d
set Model = '-'
from Devices d
where exists (select 1 from device dd where dd.model = d.model and dd.id > d.id)
After the command:
SELECT Model, count (*) FROM Devices GROUP BY model HAVING count (*)> 1;
i get the result:
1895 lines = NULL;
3383 lines with duplicate values;
and all these values are 1243.
after applying your command:
update Devices set
Model = '-'
where id not in
(select
min(Devices .id)
from Devices
group by Devices.Model)
i got 4035 lines changed.
if you count, it turns out, (3383 + 1895) = 5278 - 1243 = 4035
and it seems like everything fits together, the result suits, it works.

Using Right( command within a join: SQL

Here's what I've written. I want to adjust a field to only show the right 4 charaters within the context of a join query (e.g., a.[Plant]=b.right([Location_Code],4)), but it is not working. I must do this in order for the join to work. Please help (let me know if you need additional details):
SELECT [Plant]
,right([Location_Code],4) as DoorID
,[dtmMonthEnd]
,[DealerTIN]
,sum([Total_Acts]) as Activations
FROM [ExternalDataSources].[dbo].[Nelson_tblActivation_Activity] a
join [Commissions].[dbo].[vw_MonthlyEarnedCommission_Location] b
on a.[Plant]=b.right([Location_Code],4)
where [dtmMonthEnd] = '1/31/2016'
group by
[Plant]
,[dtmMonthEnd]
,[DealerTIN]
order by 4 asc
The full qualified column name is the argument to the right() function:
SELECT [Plant], right([Location_Code], 4) as DoorID
[dtmMonthEnd], [DealerTIN], sum([Total_Acts]) as Activations
FROM [ExternalDataSources].[dbo].[Nelson_tblActivation_Activity] a JOIN
[Commissions].[dbo].[vw_MonthlyEarnedCommission_Location] b
on a.[Plant] = right(b.[Location_Code], 4)
WHERE [dtmMonthEnd] = '2016-01-31'
GROUP BY [Plant], [dtmMonthEnd], [DealerTIN], right([Location_Code], 4)
ORDER BY DealerTIN asc;
Notes:
Use ISO standard date formats (such as YYYYMMDD or YYYY-MM-DD).
The use of column numbers for ORDER BY is being phased out. You can use the column alias.

Oracle Query on Comma Separated Values In a Column

I have two tables. One table is a list of access points. The other is a list of who has access to what.
It use to be a person had access to either one thing or all things. But, now that has changed. Now someone might have access to several points.
The wrench in the system is that in the column that shows what they have access to may have a single value, "ALL" for all access or a comma separated list (which is new).
I originally thought I could just do WHERE Access_To Here IN(), but I am unsure how to convert the value of Access_To to a formatted list.
I need to be able to do this as a single query since I am using it for a LOV in APEX.
So, I need some help.
The Access_Points_Table has only one column, Access_Points. Here are some example values that it might have:
CSX
CZR
XR3
NBO
QHG
The Users_List table has several columns, but the most important are User_Name, Access_To. Here are some example values that it might have:
Joe | ALL
Fred | CSX
Allen | CZR, NBO
Hank | QHG
Here is query I am currently using, but it only works if there is only a single value in the Access_To column.
SELECT DISTINCT Access_Points VALUE
FROM Access_Points_Table apt
JOIN
Users_List ul
ON (ul.wwid = 'ZZ999'
AND (ul.Access_To = 'ALL' OR apt.symbol_name = ul.Access_To))
ORDER BY name ASC
What I am trying to accomplish is:
SELECT DISTINCT Access_Points VALUE
FROM Access_Points_Table apt
JOIN
Users_List ul
ON (ul.wwid = 'ZZ999'
AND (ul.Access_To = 'ALL' OR apt.symbol_name IN(Something Goes Here)))
ORDER BY name ASC
So, if run a query for the user Allen, it will return the rows:
CZR
NBO
Depending on the length of your comma-delimited data, you can use Oracle's regular expression engine (the difficulty is that Oracle limits regular expressions to 512 bytes):
SELECT DISTINCT Access_Points VALUE
FROM Access_Points_Table apt
JOIN Users_List ul
ON ( ul.wwid = 'ZZ999'
AND ( ul.Access_To = 'ALL'
OR REGEXP_LIKE(apt.symbol_name, '^(' || REPLACE(ul.Access_To, ',', '|') || ')$') ) )
ORDER BY name ASC
Alternately you can use LIKE:
SELECT DISTINCT Access_Points VALUE
FROM Access_Points_Table apt
JOIN Users_List ul
ON ( ul.wwid = 'ZZ999'
AND ( ul.Access_To = 'ALL'
OR ',' || ul.Access_To || ',' LIKE '%,' || apt.symbol_name || ',%' ) )
ORDER BY name ASC
Note that if Access_To has spaces after its commas as in your OP, it does add some complexity but that can be overcome, simply REPLACE(ul.Access_To, ' ').
By the way, I do wonder why this: ul.wwid = 'ZZ999' is in the ON clause instead of in a WHERE clause.
Another way would be to use the instr test:
SELECT DISTINCT access_points VALUE
FROM access_points_table a
JOIN users_list u
ON ( INSTR(u.access_to,a.access_points,1) > 0 )
ORDER BY 1

SQL non alphabetical order in WHERE IN

Let's say I have this query:
SELECT name
FROM product
WHERE name IN ('CE367FAACDHCANPH-151556',
'CE367FAACEX9ANPH-153877',
'NI564FAACJSFANPH-162605',
'GE526OTACCD3ANPH-149839')
the result is:
CE367FAACDHCANPH-151556
CE367FAACEX9ANPH-153877
GE526OTACCD3ANPH-149839
NI564FAACJSFANPH-162605
which is ordered by the alphabetical order
How can I get a result order by the index of appearance in the list?
basically I want this as a result:
CE367FAACDHCANPH-151556
CE367FAACEX9ANPH-153877
NI564FAACJSFANPH-162605
GE526OTACCD3ANPH-149839
This is quite a popular approach to sort things in SQL, so I've blogged about this example here. You would have to explicitly order by those values in your list, e.g. using a CASE expression:
SELECT name
FROM product
WHERE name IN ('CE367FAACDHCANPH-151556',
'CE367FAACEX9ANPH-153877',
'NI564FAACJSFANPH-162605',
'GE526OTACCD3ANPH-149839')
ORDER BY CASE WHEN name = 'CE367FAACDHCANPH-151556' THEN 1
WHEN name = 'CE367FAACEX9ANPH-153877' THEN 2
WHEN name = 'NI564FAACJSFANPH-162605' THEN 3
WHEN name = 'GE526OTACCD3ANPH-149839' THEN 4
END
Example on SQLFiddle
If you want to avoid repeating those literals, you could resort to this trick:
SELECT product.name
FROM product
JOIN (
VALUES('CE367FAACDHCANPH-151556', 1),
('CE367FAACEX9ANPH-153877', 2),
('NI564FAACJSFANPH-162605', 3),
('GE526OTACCD3ANPH-149839', 4)
) AS sort (name, sort)
ON product.name = sort.name
ORDER BY sort.sort
Example on SQLFiddle
You can use PATINDEX. At least if your names have more and less the same structure.
SELECT [Name] FROM product
ORDER BY CONVERT(INT, LEFT(Name, PATINDEX('%[^0-9]%', Name+'z')-1));
Check out this example on SQL Fiddle

Filter 2-dimensional array

I have this array:
1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0,11:0,12:0,13:0,14:0,15:0,16:0
17:0,18:0,19:0,20:0,21:0,22:0,23:0,24:0,25:0,26:0,27:0,28:0,29:0,30:0,31:0,32:0,
49:0,33:0,34:0,35:0,36:0,37:0,38:0,39:0,40:0,41:0,42:0,43:0,44:0,45:0,46:0,47:0,
48:0,50:0,51:0,52:0,53:0,54:0,55:0,56:0,57:0,58:0,59:0,60:0,61:0,62:0,63:9,64:0,
65:0,66:0,67:0,68:0,69:0,70:0,71:0,72:0,73:0,74:0,75:0,76:0,77:0,78:0,79:0,80:0,
81:0,82:0,83:0,84:0,85:0,86:0,87:0,88:0,89:0,90:0,91:0,92:0,93:0,94:0,95:0,96:0,
97:0,98:0,99:0,100:0
I want to filter all entry like *:0 so that I only get this result:
63:9
I think I have to describe it better:
I have a table users with a field user_skill.
In this field is a such a string: 1:0, 2:0, 3:0, 4:3, 5:8, 6:9, 7:0, 8:0, 9:0 with this syntax: skill_id:prio,skill_id:prio,skill_id:prio,skill_id:prio,...
Now I want to to join the users table with the skills table like this:
SELECT skill_name
FROM users
inner join skills on skills.skill_id = ANY (string_to_array(regexp_replace(user_skill,':[0-9]*','','g'),',')::int[])
where user_id = 16
order by skill_name
That works well but I only want to see skill_name where the user has prio <> 0.
Proper solution
You might want to familiarize yourself with normalization and implement this as a proper n:m relation between the tables users and skills with an additional attribute prio in the user_skill table. Here is a complete recipe:
How to implement a many-to-many relationship in PostgreSQL?
Then your query can be very simple:
SELECT s.skill_name
FROM user_skill uk
JOIN skills s USING (skill_id)
WHERE uk.user_id = 16
AND uk.prio <> 0
ORDER BY s.skill_name;
It can (and should) be backed up with indices and will be faster by several orders of magnitude than what you have right now.
It will need some more space on disk.
Solution for the dark side
While being locked in this unfortunate situation you can help yourself with this query. However, this assumes at least Postgres version
SELECT s.skill_name
FROM (
SELECT split_part(us_item, ':', 1) AS skill_id
FROM (
SELECT trim(unnest(string_to_array(user_skill, ','))) AS us_item
FROM users
WHERE user_id = 16 -- enter user_id here
) x
WHERE split_part(us_item, ':', 2) <> '0'
) u
JOIN skills s USING (skill_id)
ORDER BY 1;
Demo with example:
SELECT split_part(us_item, ':', 1) AS skill_id
FROM (
SELECT trim(unnest(string_to_array(
'1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0,11:0,12:0,13:0,14:0,15:0,16:0,'
'17:0,18:0,19:0,20:0,21:0,22:0,23:0,24:0,25:0,26:0,27:0,28:0,29:0,30:0,31:0,32:0,'
'49:0,33:0,34:0,35:0,36:0,37:0,38:0,39:0,40:0,41:0,42:0,43:0,44:0,45:0,46:0,47:0,'
'48:0,50:0,51:0,52:0,53:0,54:0,55:0,56:0,57:0,58:0,59:0,60:0,61:0,62:0,63:9,64:0,'
'65:0,66:0,67:0,68:0,69:0,70:0,71:0,72:0,73:0,74:0,75:0,76:0,77:0,78:0,79:0,80:0,'
'81:0,82:0,83:0,84:0,85:0,86:0,87:0,88:0,89:0,90:0,91:0,92:0,93:0,94:0,95:0,96:0,'
'97:0,98:0,99:0,100:0', ','))) AS item
) x
WHERE split_part(us_item, ':', 2) <> '0';
trim() deals with leading and trailing spaces, like you have in your example. But those may just be artifacts in the sloppy question.
I fixed a missing ,.
BTW, the SQL standard allows to enter string literal like I demonstrate. Weird, but sometimes useful.