Oracle SQL: Limiting multiple where clauses - sql

Apologies if this seems like a duplicate to this question but I believe my use case is slightly different.
I have two tables.
Table1
ID INTCODE
-----------------------------
000019827364 1
000019829201 2
890418392101 3
890418390395 4
890418398677 5
505586578932 6
505586578914 7
505586578933 8
505586578012 9
490201827383 10
490201827466 11
001952046578 12
Table2
INTCODE Category
-------------------------
1 Display
2 Display
3 Display
4 Display
5 Display
6 Audio
7 Audio
8 Audio
9 Audio
10 Audio
11 Audio
12 Audio
My expected query results are all possible 5 digit prefixes of each category and in each of these prefixes - I want to extract at least 2 full IDs. Below is an example if I had a where clause for category as 'Display'.
ID PREFIX Category ID
-----------------------------------------------
00001 Display 000019827364
00001 Display 000019829201
89041 Display 890418392101
89041 Display 890418390395
The query I currently have is
SELECT
SUBSTR(t1.ID, 1, 5)
FROM
table1 t1
,table2 t2
WHERE
AND UPPER(t2.category) = 'DISPLAY'
AND t2.REGION_ID = 1
AND t2.ZONE_ID = 2
AND t1.REGION_ID = 1
AND t1.ZONE_ID = 2
AND t1.INTCODE = t2.INTCODE
GROUP BY
SUBSTR(t1.ID, 1, 5)
I am now kind of lost. Should I be running another query where I say
t1.ID LIKE '00001%'
OR LIKE '89041%'
This list will go on to be huge cause some of the categories have 400-500 prefixes. Is there a better way to go about this? Possibly in a single query?
I'm using Oracle SQL.
Many thanks!

You can use row_number() for this:
select Category, ID, IDPrefix
from (select Category, ID, SUBSTR(ID, 1, 5) as IDPREFIX,
ROW_NUMBER() OVER (PARTITION BY SUBSTR(ID, 1, 5) ORDER BY ID) as seqnum
FROM table1 JOIN
table2 t2
ON t1.INTCODE = t2.INTCODE ANd
t1.Region_id = t2.Region_id and
t1.zone_id = t2.zone_id
WHERE UPPER(t2.category) = 'DISPLAY'
) t
WHERE seqnum <= 2;

Assuming you can to display two rows with different Id, without any more constraint, you could simply use an union where the first query would select the max id, and the second query the min id.
So your query would look something like this
select id_prefix, category, max(id)
from yourTable
union
select id_prefix, category, min(id)
from yourTable
Now simply add to this algorithm your where conditions.

Related

Select ID with specific values in more than one field

I have a table as follows
groupCode
ProductIdentifier
1
dental
1
membership
2
dental
2
vision
2
health
3
dental
3
vision
I need to find out if a specific groupCode have "dental", "vision" and "health" (all three simultaneously)
The expected result is code 2
What I need to identify is if groupCode 2 has the three products (or two, or whatever the user enters). This is part of a huge kitchen sink query I'm building.
I'm doing
SELECT groupCode
FROM dbo.table
WHERE (productIdentifier = N'dental')
AND (productIdentifier = N'vision')
AND (productIdentifier = N'health')
AND (groupCode = 2)
But clearly is wrong because it's not working.
I tried to do something like its described here but it didn't return a result for me:
Select rows with same id but different value in another column
Thanks.
If each of 'dental','vision' and 'health' occur only once per group identifier, you can group by group identifier and filter by the groups having count(*) = 3:
WITH
-- your input ..
indata(groupCode,ProductIdentifier) AS (
SELECT 1,'dental'
UNION ALL SELECT 1,'membership'
UNION ALL SELECT 2,'dental'
UNION ALL SELECT 2,'vision'
UNION ALL SELECT 2,'health'
UNION ALL SELECT 3,'dental'
UNION ALL SELECT 3,'vision'
)
-- real query starts here ...
SELECT
groupcode
FROM indata
WHERE productidentifier IN ('dental','vision','health')
GROUP BY
groupcode
HAVING COUNT(*) = 3;
-- out groupcode
-- out -----------
-- out 2
As per Marcothesane answer, if you know the groupCode (2) and the number of products (vision, dental and health), 3 in this case, and you need to confirm if that code has those three specific products, this will work for you:
SELECT COUNT(groupCode) AS totalRecords
FROM dbo.table
WHERE (groupCode = 2) AND (productIdentifier IN ('dental', 'vision', 'health'))
HAVING (COUNT(groupCode) = 3)
This will return 3 (number of records = number of products).
Its basically's Marcothesane answer in a way you can "copy/paste" to your code by just changing the table name. You should accept Marcothesane answer.

UNION table in second query based on the result of first query in Oracle sql

I am struggling with following problem (in further I provide pseudocode in order to make my example more understandable)
Assume I have 2 queries which result I want to union with each other
What query1 output looks like:
ID OFFER
1 prod_1
2 prod_2
3 prod_2
4 prod_1
What query2 output looks like:
ID SEGMENT
1 LOW
2 HIGH
3 MED
999 MED
What I need to do is to union results of this 2 queries, but avoid taking row with ID = 999
If there any way to do it using UNION by extracting from query2 rows bases on values of column ID which are present in column ID of query2?
I know that following code is incorrect but it conveys the idea of ​​the question greatly:
--query1
(
SELECT ID, OFFER
FROM TAB1
WHERE ID <= 4
) RES1
UNION
--query2
SELECT ID, SEGMENT
FROM TAB1
WHERE ID IN (SELECT ID FROM RES2)
Result should be as following
ID OFFER
1 prod_1
2 prod_2
3 prod_2
4 prod_1
1 LOW
2 HIGH
3 MED
Appreciate your help
Your pseudo code comes very close. You can use WITH for convenience:
WITH q1 AS (SELECT id, offer FROM tab1 WHERE id <= 4)
, q2 AS (SELECT id, segment FROM tab1 WHERE id IN (SELECT id FROM q1))
SELECT * FROM q1
UNION ALL
SELECT * FROM q2;
(Be aware though that you can get the rows in any order, if you don't specify an ORDER BY clause.)

How do I aggregate numbers from a string column in SQL

I am dealing with a poorly designed database column which has values like this
ID cid Score
1 1 3 out of 3
2 1 1 out of 5
3 2 3 out of 6
4 3 7 out of 10
I want the aggregate sum and percentage of Score column grouped on cid like this
cid sum percentage
1 4 out of 8 50
2 3 out of 6 50
3 7 out of 10 70
How do I do this?
You can try this way :
select
t.cid
, cast(sum(s.a) as varchar(5)) +
' out of ' +
cast(sum(s.b) as varchar(5)) as sum
, ((cast(sum(s.a) as decimal))/sum(s.b))*100 as percentage
from MyTable t
inner join
(select
id
, cast(substring(score,0,2) as Int) a
, cast(substring(score,charindex('out of', score)+7,len(score)) as int) b
from MyTable
) s on s.id = t.id
group by t.cid
[SQLFiddle Demo]
Redesign the table, but on-the-fly as a CTE. Here's a solution that's not as short as you could make it, but that takes advantage of the handy SQL Server function PARSENAME. You may need to tweak the percentage calculation if you want to truncate rather than round, or if you want it to be a decimal value, not an int.
In this or most any solution, you have to count on the column values for Score to be in the very specific format you show. If you have the slightest doubt, you should run some other checks so you don't miss or misinterpret anything.
with
P(ID, cid, Score2Parse) as (
select
ID,
cid,
replace(Score,space(1),'.')
from scores
),
S(ID,cid,pts,tot) as (
select
ID,
cid,
cast(parsename(Score2Parse,4) as int),
cast(parsename(Score2Parse,1) as int)
from P
)
select
cid, cast(round(100e0*sum(pts)/sum(tot),0) as int) as percentage
from S
group by cid;

Returning several rows from a single query, based on a value of a column

Let's say I have this table:
|Fld | Number|
1 5
2 2
And I want to make a select that retrieves as many Fld as the Number field has:
|Fld |
1
1
1
1
1
2
2
How can I achieve this? I was thinking about making a temporary table and instert data based on the Number, but I was wondering if this could be done with a single Select statement.
PS: I'm new to SQL
You can join with a numbers table:
SELECT Fld
FROM yourtable
JOIN Numbers
ON yourtable.Number <= Numbers.Number
A numbers table is just a table with a list of numbers:
Number
1
2
3
etc...
Not an great solution (since you still query your table twice, but maybe you can work from it)
SELECT t1.fld, t1.number
FROM table t1, (
SELECT ROWNUM number FROM dual
CONNECT BY LEVEL <= (SELECT MAX(number) FROM t1)) t2
WHERE t2.number<=t1.number
It generates maximum amount of rows needed and then filters it by each row.
I don't know if your RDBMS version supports it (although I rather suspect it does), but here is a recursive version:
WITH remaining (fld, times) as (SELECT fld, 1
FROM <table>
UNION ALL
SELECT a.fld, a.times + 1
FROM remaining as a
JOIN <table> as b
ON b.fld = a.fld
AND b.number > a.times)
SELECT fld
FROM remaining
ORDER BY fld
Given your source data table, it outputs this (count included for verification):
fld times
=============
1 1
1 2
1 3
1 4
1 5
2 1
2 2

Add Column values in sql server query

I have result of two queries like:
Result of query 1
ID Value
1 4
2 0
3 6
4 9
Result of query 2
ID Value
1 6
2 4
3 0
4 1
I want to add values column "Value" and show final result:
Result of Both queries
ID Value
1 10
2 4
3 6
4 10
plz guide me...
select id, sum(value) as value
from (
select id, value from query1
uninon all
select id, value from query2
) x
group by id
Try using a JOIN:
SELECT
T1.ID,
T1.Value + T2.Value AS Value
FROM (...query1...) AS T1
JOIN (...query2...) AS T2
ON T1.Id = T2.Id
You may also need to consider what should happen if there is an Id present in one result but not in the other. The current query will omit it from the results. You may want to investigate OUTER JOIN as an alternative.
A not particularly nice but fairly easy to comprehend way would be:
SELECT ID,SUM(Value) FROM
(
(SELECT IDColumn AS ID,ValueColumn AS Value FROM TableA) t1
OUTER JOIN
(SELECT IDColumn AS ID,ValueColumn AS Value FROM TableB) t2
) a GROUP BY a.ID
It has the benefits of
a) I don't know your actual table structure so you should be able to work out how to get the two 'SELECT's working from your original queries
b) If ID doesn't appear in either table, that's fine