SQL limiting Count function based on IN clause using comma delimited list - sql

I have a table of Matricies (JobMatricies) ID, Desc, DeptIDs
1 Admin (PM) 6,7,138,131,11,9,10,134,135,14,105,129
5 Sales Processing (PM) 92,16,153,17,91,32,26,93,99,18,89,90,155,19
6 Construction Processing (PM) 100,36,20,136,22,88,23,25,34,106,38,39,132,41,42,43,154,152,84
DeptIDs are a Comma Delimited list of departments that I want to use to count how many records are represented by the Matrix.
Normally I would do something like....
select Matrix_ID,
Matrix_Desc,
JobCount = (select count(sched_ID) from JobSchedule where dept_ID in (**92,16,153,17,91,32,26,93,99,18,89,90,155,19**))
from jobMatrices
How do I replace the hard coded delimited string with the ID's stored with each matrix, so that I can produce a list of matricies with their own unique count based on the comma delimited string that is stored with each matrix.
Thanks

I just answered a similar question where the poster wanted to sum the delimited list of numbers in a similar table layout. My solution used CTE's in Oracle to turn that list into a CTE table which would allow you to join against it. I believe that technique would be of use here if your RDBMS supports that. Please have a look: https://stackoverflow.com/a/38231838/2543416

select s.ID
, m."Desc"
from JobSchedule s
, jobMatrices m
where position(',' || s.ID || ',' in ',' || m.DeptIDs || ',')>0;
select m."Desc"
, count(s.ID) JobCount
from JobSchedule s
, jobMatrices m
where position(',' || s.ID || ',' in ',' || m.DeptIDs || ',')>0
group by m."Desc";

In MySQL, you can treat a comma-separated string as a SET, and there's a builtin function FIND_IN_SET() that helps:
select m.Matrix_ID,
m.Matrix_Desc,
(select count(sched_ID) from JobSchedule
where FIND_IN_SET(dept_ID, m.DeptIds)) AS JobCount
from jobMatrices AS m;
This will have terrible performance, however.
If you use some RDBMS other than MySQL, they may have a different solution that works similarly.
You should be specific in your question and tag your question appropriately. You only tagged your question sql, but this is a language used by many RDBMS vendors.

Related

DB2 -Clause IN-Multiple Value

The following code is working fine when the column 'generated_key ' return one value
WHERE code IN ( SELECT generated_key FROM List_agg )
CODE
generated_key
EU00100ST10000016
EU00100ST10000016
But when the column generated_key containt more than a values, it return 0 rows
CODE
generated_key
EU00100ST10000016
EU00100ST10000016, EU00100ST10000017
If you need to compare to a list, use delimited comparisons
WHERE EXISTS (SELECT 1
FROM list_agg
WHERE ',' || generated_key || ',' LIKE '%,' || code ',%'
)
The "list_agg" name suggests that you are aggregating values from another query. If so, you might be able to use use in with no aggregation. But your question doesn't have enough details to know if that is really the case.

How to fetch only a part of string

I have a column which has inconsistent data. The column named ID and it can have values such as
0897546321
ABC,0876455321
ABC,XYZ,0873647773
ABC,
99756
test only
The SQL query should fetch only Ids which are of 10 digit in length, should begin with a 08 , should be not null and should not contain all characters. And for those values, which have both digits and characters such as ABC,XYZ,0873647773, it should only fetch the 0873647773 . In these kind of values, nothing is fixed, in place of ABC, XYZ , it can be anything and can be of any length.
The column Id is of varchar type.
My try: I tried the following query
select id
from table
where id is not null
and id not like '%[^0-9]%'
and id like '[08]%[0-9]'
and len(id)=10
I am still not sure how should I deal with values like ABC,XYZ,0873647773
P.S - I have no control over the database. I can't change its values.
SQL Server generally has poor support regular expressions, but in this case a judicious use of PATINDEX is viable:
SELECT SUBSTRING(id, PATINDEX('%,08[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9],%', ',' + id + ','), 10) AS number
FROM yourTable
WHERE ',' + id + ',' LIKE '%,08[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9],%';
Demo
If you normalise your data, and split the delimited data into parts, you can achieve this some what more easily:
SELECT SS.value
FROM dbo.YourTable YT
CROSS APPLY STRING_SPLIT(YT.YourColumn,',') SS
WHERE LEN(SS.value) = 10
AND SS.value NOT LIKE '%[^0-9]%';
If you're on an older version of SQL Server, you'll have to use an alternative String Splitter method (such as a XML splitter or user defined inline table-value function); there are plenty of examples on these already on Stack Overflow.
db<>fiddle

Teradata Concatenate multiple rows using XMLAGG getting issue in XmlAgg function or any equivalent logic to concatendate multiple rows

I have a table of record tried to concatenate multiple rows on group wise and i use XMLAGG function but when i try to run the query for particular group which has 2000 records, getting error message:
Select failed 9134 : Intermediate aggregate storage limit for aggregation has been exceeded during computation
SELECT
H.GROUP_id,
H.Group_name,
TRIM(
TRAILING ',' FROM (
XMLAGG(TRIM(COALESCE(H.Group_desc, -1) || '') ORDER BY H.LINE_NBR) (VARCHAR(7000))
)
) AS Group_detail
even increased the varchar value but still having same issue
XMLAGG() adds overhead. However, you can get a sense for how large the result set is by using:
SELECT H.GROUP_id, H.Group_name,
SUM(LENGTH(COALESCE(H.Group_Desc, '-1'))) as total_string_length,
COUNT(*) as cnt
FROM . . .
GROUP BY H.GROUP_id, H.Group_name
ORDER BY total_string_length DESC
You will probably find that some of the groups have total string close to or more than 7000 characters.
I'm not sure if you want to fix the data or do something else. But this should at least identify the problem.
The problem is that the concatenation would be repeated for every row in the dataset, you need to get the distinct Group_desc first, try this:
WITH BASE AS(
SEL
H.GROUP_id,
H.Group_name,
H.Group_desc,
MAX(H.LINE_NBR) AS LINE_NBR
FROM TABLE_NAME
GROUP BY 1,2,3
)
SELECT
BASE.GROUP_id,
BASE.Group_name,
TRIM(
TRAILING ',' FROM (
XMLAGG(TRIM(COALESCE(BASE.Group_desc, -1) || '') ORDER BY BASE.LINE_NBR) (VARCHAR(7000)) -- You probably won't need the varchar to be that large.
)
) AS Group_detail
FROM BASE

How to use cursor with LISTAGG in PL/SQL?

I have used LISTAGG to concatenate data from two different tables to form the following output:
How do I display the above output neatly like this:
I am using ORACLE PL/SQL. I am thinking if this can be done by implementing cursor, but I am not sure how to do it. Or maybe is there any other way to achieve this? Thanks.
Looks like NATION.N_NAME column's datatype is CHAR as those names are blank-padded. I'd switch to VARCAHR2 (if possible) or try with TRIM, e.g.
select ...
listagg(trim(n.n_name), ', ') within group ...
----
this
WITH CTE AS
(SELECT r.REGION_KEY
,r.R_NAME
,LIST_AGG(trim(n.N_NAME),',') WITHIN GROUP (ORDER BY R_NAME) AS REGION_NATION
FROM REGION r
INNER JOIN NATION n
ON r.R_REGION_KEY = n.N_REGIONKEY
GROUP BY r.R_REGION_KEY
,r.R_NAME
)
SELECT REGION_KEY
,R_NAME || ':' || REGION_NATION as REGION_TEXT
FROM CTE

How to add a title and substring

I need to get a list of names as per the following format
"Mr."+first name initial+last name+"."
There is only one table for this
salesperson (f_name, l_name)
What i have been trying is;
SELECT 'Mr.' ||' ' || SUBSTRING(f_name,1,1) || ' ' || l_name ||’.’||
FROM salesperson;
It works without the substring or left, but not if I include them.
Use concat instead of || operator to concatenate strings in MySQL. As you have it, it would be interpreted as logical OR condition, hence you get the error.
SELECT CONCAT('Mr.',' ',SUBSTRING(f_name,1,1),' ',l_name,'.')
FROM salesperson;
Oracle solution
SELECT 'Mr.'||' '||SUBSTR(f_name,1,1)||' '||l_name||'.'
FROM salesperson;
It is better practice anyways to grab the name data in full and then format it in the view part of your application with languages that are more suited to string manipulation. This also makes your code more reusable.
That being said use this
SELECT CONCAT("Mr. ",SUBSTRING( f_name, 1, 1 ) ," ",l_name,".") FROM salesperson