How to select multiple values with the same ids and put them in one row, while maintaining the id to value connection? - sql

I have a processknowledgeentry table that has the following data:
pke_id prc_id knw_id
1 1 2
2 1 4
3 2 4
The column knw_id references another table called knowledge, which also has its own id column. I want to be able to select all knw_id values with the same prc_id, and have them retain its nature as an id (so that it remains referenceable to the knowledge table).
Desired result:
prc_id knw_ids
1 [2, 4]
My code is shown below. (It also selects a Process Name from another table called process by inner joining the prc_ids. That part works correctly at least.)
SELECT * FROM (
SELECT
p.prc_name,
(SELECT knw_id
FROM processknowledgeentry
GROUP BY knw_id
HAVING COUNT(*) > 1)
FROM processknowledgeentry pke
INNER JOIN process p
ON pke.prc_id=p.prc_id
WHERE pke.prc_id = %s) as temp
I get the error: "CardinalityViolation: more than one row returned by a subquery used as an expression", and I understand why the error exists, so I want to know how to work around it. I'm also not sure if my logic is correct.
Would appreciate any assistance, thank you!

Seems you need a STRING_AGG() function instead of GROUP_CONCAT(), which some other DBMS has, containing a string type parameter as the first argument along with HAVING clause which filters multiple prc_id values such as
SELECT p.prc_id, STRING_AGG(knw_id::TEXT,',') AS knw_ids
FROM processknowledgeentry pke
JOIN process p
ON pke.prc_id = p.prc_id
-- WHERE pke.prc_id = %s
GROUP BY p.prc_id
HAVING COUNT(pke.prc_id) > 1
Indeed this case, a WHERE clause won't be needed.
Demo

Related

Why can't I get GROUP BY to work in my LEFT JOIN in Access

I'm trying to populate a combobox from two tables in Access (2007-2016 file format).
I have two tables:
tblSurveyStatus
SurveyID
SurveyStatus
1
Y
2
N
3
N/A
tblWorkOrder
WONumber
SurveyedID
WO2101
1
WO2102
1
WO2103
2
WO2104
3
WO2105
2
WO2106
{Empty}
WO2107
{Empty}
Desired Result:
WONumber(this col will get hidden)
SurveyStatus
WO2101
Y
WO2103
N
WO2104
N/A
This query works in the datasource for the combobox without using GROUP BY:
SELECT SurveyedID, SurveyStatus
FROM [tblWorkOrders] a
LEFT JOIN (
SELECT SurveyID, SurveyStatus
FROM [tblSurveyStatus]
) b
ON a.SurveyedID = b.SurveyID
ORDER BY b.SurveyID
The problem with this query is that it returns duplicates (Y,Y,N,N,N/A).
So I introduced the GROUP BY like this:
SELECT SurveyedID, SurveyStatus
FROM [tblWorkOrders] a
LEFT JOIN (
SELECT SurveyID, SurveyStatus
FROM [tblSurveyStatus]
) b
ON a.SurveyedID = b.SurveyID
GROUP BY a.SurveyStatus ORDER BY b.SurveyID
This causes an error message "Your query does not include the specified expression 'SurveyedID' as part of an aggregate function." So, I put MIN(SurveyedID) and the error message moves to the next field so I keep putting MIN() in the SQL until finally it works but, I get an input box asking for the "SurveyStatus" then another one asking for the "SurveyID".
I have spent three solid days researching, reading threads on this website and many others without success. I am not a programmer but I kind of understand the basics. My programming basically comes from finding snippets of code and altering them for my use. Please Help!
You are using 2 columns : SurveyedID, SurveyStatus in your 'select' expression while in 'group by' you are using only SurveyStatus which is not valid. All non-aggregate columns in select should be used in 'group by' as well. That is why by adding MIN() to those columns solved the error (which converted those non-aggregate columns to aggregate ones).
Adding "SurveyedID" also to your group by clause can resolve your issue here.
Also if your sole motive is to avoid duplicates , just use 'DISTINCT' before the list of columns in select expression

Athena/Presto | Can't match ID row on self join

I'm trying to get the bi-grams on a string column.
I've followed the approach here but Athena/Presto is giving me errors at the final steps.
Source code so far
with word_list as (
SELECT
transaction_id,
words,
n,
regexp_extract_all(f70_remittance_info, '([a-zA-Z]+)') as f70,
f70_remittance_info
FROM exploration_transaction
cross join unnest(regexp_extract_all(f70_remittance_info, '([a-zA-Z]+)')) with ordinality AS t (words, n)
where cardinality((regexp_extract_all(f70_remittance_info, '([a-zA-Z]+)'))) > 1
and f70_remittance_info is not null
limit 50 )
select wl1.f70, wl1.n, wl1.words, wl2.f70, wl2.n, wl2.words
from word_list wl1
join word_list wl2
on wl1.transaction_id = wl2.transaction_id
The specific issue I'm having is on the very last line, when I try to self join the transaction ids - it always returns zero rows. It does work if I join only by wl1.n = wl2.n-1 (the position on the array) which is useless if I can't constrain it to a same id.
Athena doesn't support the ngrams function by presto, so I'm left with this approach.
Any clues why this isn't working?
Thanks!
This is speculation. But I note that your CTE is using limit with no order by. That means that an arbitrary set of rows is being returned.
Although some databases materialize CTEs, many do not. They run the code independently each time it is referenced. My guess is that the code is run independently and the arbitrary set of 50 rows has no transaction ids in common.
One solution would be to add order by transacdtion_id in the subquery.

How to save data in SQL and loop on it?

once i run first query i got the below result:
REQUEST_NO R
---------- -
4309300 A
4300983 C
and i want to compare if R column is different to "C" run second query and do the same for each element that i can have in REQUEST_NO column different to C
SELECT REQUEST_NO
, REQUEST_STS
FROM PORT_REQUEST
WHERE REQUEST_NO IN (SELECT DISTINCT REQUEST_NO
FROM SUB_PORT_REQUEST
WHERE SUBSCRIBER_NO = replace(replace('&CTN','-',''),' ',''));
Enter value for ctn: 5161890110
REQUEST_NO R
---------- -
4309300 A
4300983 C
SELECT ACT_SEQ_NO
FROM SUB_PORT_REQUEST
WHERE REQUEST_NO=&Req_No
AND ROWNUM <=1
ORDER BY ACT_SEQ_NO DESC;
Enter value for req_no: 4309300
ACT_SEQ_NO
----------
91180671
I expect to save in a array or something all values and can be able to iterate on it, can someone help?
One option, if you want to remain in SQL*Plus, is to create a (global temporary?) table, store result of the first query into it, and then rewrite the second query to use those results as
where request_no in (select request_no from my_temporary_table)
Another is to switch to PL/SQL and write a procedure which will accept CTN as a parameter. It (PL/SQL) allows you to use different ways to store results of the first query - into a table (as previously) or an array.
You can combine these to just 1 query by joining the tables. I am not sure I know how to handle the segment "and rownum<=1 Order by ...". Either the order by clause is not needed as rownum<=1 will produce at most 1 row and no matter how you sort it 1 row always comes out the same. Or you expect multiple rows want only want the greatest act_seq_no. If that is the case you need the order by in a sub-query and the rownum predicate on the outer. Assuming the latter we get:
Also assuming the column you refer to as R in description is actually the column port_request.request_sts as R is NOT selected nor is it an alias for any referenced column given.
select act_seq_no
from ( select spr.act_seq_no
from sub_port_request spr
join port_request pr
on (spr.request_no = pr.request_no and
pr.request_sts != 'C'
)
where spr.subscriber_no = replace(replace('&CTN','-',''),' ','')
order by spr.act_seq_no desc
)
where rownum<=1;

SQL SELECT returns same item more than one time

I have the following SQL Command:
SELECT *
FROM Notes
INNER JOIN AuthorizedPersons
ON Notes.idPass = AuthorizedPersons.idPass
AND AuthorizedPersons.Privileged = 0
AND Notes.idUser =7
This returns the correct items! BUT returns the same item twice for each AuthorizedPerson that exists!
(Using DISTINCT does not solve the problem because items can have the same name.)
Query Results:
As you can see in the idPass 15 and 16 the description can be the same BUT idPass cannot since it's the primary key!
The query returns 3 times the idPass 30...
Try to use Where instead of the first AND.
SELECT *
FROM Notes
INNER JOIN AuthorizedPersons
ON Notes.idPass = AuthorizedPersons.idPass
WHERE AuthorizedPersons.Privileged = 0
AND Notes.idUser =7
In the table AuthorizedPersons ,column starting with 'IdUs..' repeating multiple times against the same idPass.That is why you are getting multiple rows against same value of idpass.For avoiding the duplicate records, you can either use a 'DISTINCT' keyword after excluding that particular column or you can choose any one of the record from that duplicated record by eliminating the others.

SQL Group on a combination of values

I'm working a DB design regarding how a user launched something.
My idea was to have timestamp (DateTime) column, and a method column (varchar).
This 'method' (varchar) could be anything:
BUTTON_OK
BUTTON_X
APP_Y
APP_Z
etc
How can I COUNT the uses but group some values. In this case I want to have my result:
BUTTONS: 20
APP_X: 10
APP_Z: 14
You need some way of defining which 'methods' fall into which 'method group'.
One way would be to have a lookup table:
tbl_methodgroup
method_id Method Method_group
1 Button_OK Buttons
2 Button_X Buttons
3 App_Y App_Y
4 App_Z App_Z
then you could use:
select
b.method_group,
count(1)
from
tbl_methodgroup a
inner join tbl_method b on a.Method=b.Method
group by b.method_group
This method would have the advantage of being scalable as more methods get added. Rather than hand coding queries, which would need to be modified each time.
If the name of the table is tblTest, then the query will look like following:
SELECT method, COUNT(*) FROM tblTEst Group BY method
Apologies if I missread question, last chance to make it right if you have consistency in the data and grouping scenarios you can do following:
SELECT LEFT(method,CHARINDEX('_',method)-1),
COUNT(*)
FROM tblTest
GROUP BY LEFT(method,CHARINDEX('_',method)-1)
Otherwise Stuart Moore's answer is correct one.