I have a database full of Chemical Data. In a table, each row of course contains a set of columns. One of these is what I want; the ID. One of these is what I am trying to identify the row by; cas_number.
I want to make a query or script that can take a list eg; (77-58-7, 77-58-7, 12578-12-0,...) and return the respective ID for each cas_number in the list.
So far I have tried to use the basic WHERE IN (_) query, only to get errors. After Googling around for a while I found nothing else probably due to the weird wording of my question. Hopefully typed out it makes more sense.
Edit to add sample data in CSV format.
id,cas_number
515,77-58-7
123,77-99-6
12,101-02-0
564,126-58-9
321,2452-01-9
624,12065-90-6
643,12202-17-4
15,12578-12-0
62,15535-79-2
77,15546-11-9
536,15571-58-1
55,15647-08-2
33,25448-25-3
22,25550-98-5
326,26544-23-0
123,27107-89-7
321,32509-66-3
234,35674-68-1
543,57583-34-3
456,57583-35-4
765,62229-08-7
53,68109-88-6
31,77745-66-5
86,91031-62-8
First make a table from your list using unnest and then join.
select id, cas_number
from _table
inner join unnest(string_to_array('4141-41-53, 535-35-135, 5136-662-32', ', ')) v
on cas_number = v;
or as a parameterized query -
select id, cas_number
from _table
inner join unnest(string_to_array(:cas_list, ', ')) v on cas_number = v;
Ordering the result :
select id, cas_number
from _table
inner join unnest(string_to_array(:cas_list, ', ')) with ordinality t(v, o)
on cas_number = t.v
order by t.o;
I am having to write a query for an AS400 report. We are looking to group data by date. In other words we want to sum all data for each individual year and month. This is the query I have currently:
Select SCDATA.SCCLNT.CCLNT,
(Select SCDATA.SCCLNT.CNAME From SCDATA.SCCLNT
Where SCDATA.SCCLNT.CLTGRP Like 916500 Fetch First 1 Rows Only) As ClientName,
CONCAT(TRIM(SCDATA.SCCLNT.CADD1), SCDATA.SCCLNT.CADD2) As Address1,
CONCAT(TRIM(SCDATA.SCCLNT.CCITY), CONCAT(', ',
CONCAT(TRIM(SCDATA.SCCLNT.CSTATE), CONCAT(' ', TRIM(SCDATA.SCCLNT.CZIP)))))
As Address2,
SCDATA.SCCLNT.CLTGRP As Group,
SCDATA.SCPLHS.HMONTH || '-' || SCDATA.SCPLHS.HYEAR AS EndDate,
sum(HPL#) as Placed#,
sum (hpl$) as Placed$,
sum(HPMT$M) as PymtMth,
sum(HPMT$) as PymtTTL,
sum(HCOM$) as CommTTL,
sum(HPIF#) as PIF,
sum(HCLI#) as WithDrawn#,
sum(HCLI$) as WithDrawn$,
sum(HCLA#) as Closed#,
sum(HCLA$) as Closed$,
sum(HPMT$)/sum(HPL$) as Recovered,
sum(HAC#) as Active#,
sum(HAC$) as Active$
From SCDATA.SCCLNT
Inner Join SCDATA.SCPLHS On SCDATA.SCPLHS.HCLNT = SCDATA.SCCLNT.CCLNT And
(SCDATA.SCPLHS.HYEAR Between 17 And 17) and
(SCDATA.SCPLHS.HMONTH Between 01 And 10 )
Where SCDATA.SCCLNT.CLTGRP Like 916500
Group By SCDATA.SCPLHS.HYEAR ,
SCDATA.SCPLHS.HMONTH,
SCDATA.SCCLNT.CCLNT,
SCDATA.SCCLNT.CADD1,
SCDATA.SCCLNT.CADD2,
SCDATA.SCCLNT.CZIP,
SCDATA.SCCLNT.CLTGRP,
SCDATA.SCCLNT.CCITY,
SCDATA.SCCLNT.CSTATE
How can I collate this date so that my results show each date only once, and the sum of all data for that date?
Than you.
--EDIT--
Here are the results I am getting from the current query, tab delimited:
https://drive.google.com/open?id=0BwJ_JKr6NhYJVnNIVDcyNW9WMms CSV File
The results I need are:
https://drive.google.com/open?id=0BwJ_JKr6NhYJUTBDUTlDV00yanc
When I was grouping the query results I was including the SCCLNT column in the group. Each client group has multiple client numbers, which was causing the query to return multiple results, one for every client ID.
You statement has an aggregation problem - your GROUP BY includes two separate tables, the columns of which are not going to share an index (and quite possibly one of the tables may not have an index over the used columns at all). The statement is going to be slower than it needs to be.
You may find it more faster to do the aggregation just on the actual sale data:
SELECT Client.group, Client.name, Client.address1, Client.address2,
Historical.month || '-' || Historical.year as endDate
Historical.placed#, Historical.placed$,
Historical.pymtMth,
Historical.pymtTTL, Historical.commTTL,
Historical.PIF,
Historical.withdrawn#, Historical.withdrawn$,
Historical.closed#, Historical.closed$,
Historical.recovered,
Historical.active#, Historical.active$
FROM (SELECT SCPlHs.hYear as year,
SCPlHs.hMonth as month,
SUM(SCPlHs.hPl#) as placed#,
SUM(SCPlHs.hPl$) as placed$,
SUM(SCPlHs.hpmt$m) as pymtMth,
SUM(SCPlHs.hPmt$) as pymtTTL,
SUM(SCPlHs.hCom$) as commTTL,
SUM(SCPlHs.hPif#) as PIF,
SUM(SCPlHs.hCli#) as withdrawn#,
SUM(SCPlHs.hCli$) as withdrawn$,
SUM(SCPlHs.hCla#) as closed#,
SUM(SCPlHs.hCla$) as closed$,
SUM(SCPlHs.hPmt$) / SUM(SCPlHs.hpl$) as recovered,
SUM(SCPlHs.hAc#) as active#,
SUM(SCPlHs.hAc$) as active$
FROM SCData.SCPlHs
JOIN (SELECT DISTINCT cClnt as client
FROM SCData.SCClnt
WHERE SCClnt.cltGrp = 916500) Client
ON Client.client = SCPlHs.hClnt
-- dates, like all positive, contiguous-range types,
-- should be queries with an exclusive upper bound.
-- You should stop using BETWEEN, if possible.
WHERE SCPlHs.hYear >= 17 and SCPlHs.hYear < 18
AND SCPlHs.hMonth >= 1 and SCPlHs.hMonth < 11
GROUP BY SCPlHs.hYear, SCPlHs.hMonth) Historical
-- Cross joins multiply the total number of rows, but that's okay here because
-- the joined table is going to only have one row
CROSS JOIN (SELECT SCClnt.cltGrp as group
SCClnt.cName as name,
TRIM(SCClnt.cAdd1) || TRIM(SCClnt.cAdd2) as address1,
TRIM(SCClnt.cCity) || ', ' || TRIM(SCClnt.cState) || ' ' || TRIM(SCClnt.cZip) as address2
FROM SCData.SCClnt
WHERE SCClnt.cltGrp = 916500
FETCH FIRST 1 ROW ONLY) Client
ORDER BY Historical.year, Historical.month
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.
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;