Oracle SQL to get min number from case statement - sql

I have this query below (in Oracle PL/SQL) which I am trying to pull a price, it seems to give me 3 records but I only want one. I want to show the lowest rate if I run into this kind of scenario, can I possibly put a min function around the 'rate' field which is in the case statement below?
select /*+ rule */ a.skucode as skucode,a.sizecode as
sizecode,b.colourdescription as colourdesc, a.season as season,
(case when sp.eventnbr in (select eventnbr from event where sysdate
between eventbegints
and eventendts) then rate else sellprice end) as listprice
from sku a, colour b, skuprcevnt sp
where a.skucode = '00000000051361264-04'
--" and a.storecode = '00000' " +
and a.storecode = '00000'
and a.colourcode = b.colourcode
and a.skucode=sp.skucode(+)
order by a.skucode, a.sizecode, b.colourdescription;
This gives the following result (but I want to see the price of 76.99 only):
SKUCODE SIZECODE COLOURDESC SEASON LISTPRICE
00000000051361264-04 XL BLACK FA-13 155
00000000051361264-04 XL BLACK FA-13 155
00000000051361264-04 XL BLACK FA-13 76.99

You can use MIN in the column list if you group the query appropriately:
select a.skucode,
a.sizecode,
b.colourdescription as colourdesc,
a.season,
MIN(case
when sp.eventnbr in (select eventnbr
from event
where sysdate between eventbegints
and eventendts)
then rate
else sellprice
end) as listprice
from sku a
INNER JOIN colour b
ON b.colourcode = a.colourcode
LEFT OUTER JOIN skuprcevnt sp
ON sp.skucode = a.skucode
where a.skucode = '00000000051361264-04' and
a.storecode = '00000'
GROUP BY a.SKUCODE, a.SIZECODE, b.COLOURDESCRIPTION, a.SEASON
order by a.skucode, a.sizecode, b.colourdescription, a.SEASON;
Share and enjoy.

The contents of your select clause will never affect the number of rows returned by a query. You need a filter in the WHERE clause along the lines of WHERE rate = (select min(rate) sku where skucode=a.skucode ).
Your example is more complicated so the actual filter would be bigger but that's just an idea of what it would look like.

Related

Updating a value in a Select based on a Greater Than clause

I'm attempting to make a SQL report that would identify the current on hand quantity. The value listed in the select would display the given value in the table unless a rule is applied.
Essentially, I need assistance on how to write the IF statement.
SELECT itemno
,QOHQTY
,SAFETYSTOCKQTY
FROM EDI846OutboundDetail WITH (NOLOCK)
WHERE PARTNERID = '987654321'
AND itemno = '123465'`
This select would return
itemno QOHQTY SAFETYSTOCKQTY
123465 3.00000000 12.00000000
However, since SAFETYSTOCKQTY is greater than 3, then the select should return a ZERO in QOHQTY. If it is not, then it should continue to display 3 in QOHQTY.
I've been looking to use both an IF statement in a temp table, but I was trying to avoid that. Likewise, I discovered a WHERE CASE statement that may work, such as this example below.
SELECT '1'
FROM EDI846OutboundDetail WITH (NOLOCK)
WHERE CASE WHEN SAFETYSTOCKQTY > 1 THEN '1'
END
and PARTNERID = '987654321'
AND itemno = '123465'
However, I was having troubles with how to format that code.
since SAFETYSTOCKQTY is greater than 3, then the select should return a ZERO in QOHQTY. If it is not, then it should continue to display 3 in QOHQTY.
Use CASE:
SELECT
itemno,
CASE WHEN safetystockqty > 3 THEN 0 ELSE qohqty END qohqty,
safetystockqty
FROM EDI846OutboundDetail WITH (NOLOCK)
WHERE partnerid = '987654321' AND itemno = '123465'`
Or maybe, as commented by averey_larry, you want to compare safetystockqty against the value of qohqty? Then:
SELECT
itemno,
CASE WHEN safetystockqty > qohqty THEN 0 ELSE qohqty END qohqty,
safetystockqty
FROM EDI846OutboundDetail WITH (NOLOCK)
WHERE partnerid = '987654321' AND itemno = '123465'`

Returning '0' in DB2 if there are no records or count is zero

I'm trying to get this working query to return 0 as the value if no rows are found and count is 0.
I've tried IFNULL with a zero, coalesce and 'then 1 else 0' but nothing works and I just get blank rows.
Query in db2:
select
cust,
'PRIOR' as Range,
coalesce(count(case when fordate between '2017-01-01' and '2017-04-13' then 1
else 0 end),0)as count
from table1
where cust = 123
For the ELSE condition of your call to COUNT, you should count NULL, which will then be ignored in the count:
SELECT
123 AS cust,
'PRIOR' AS Range,
COUNT(CASE WHEN fordate BETWEEN '2017-01-01' AND '2017-04-13' AND cust = 123
THEN 1 END) AS count
FROM table1;
Note that I left out the actual ELSE condition, because the default value if not specified explicitly is NULL. Also, I moved the WHERE condition into the conditional count. This will have the effect that one row will always be returned, even if that customer does not even appear in the table.
Selecting cust look off, because you are doing a count over the entire table. I would have done SELECT 123 AS cust, ..., but if DB2 allows this syntax, then so be it.
If your table has no row for customer 123, you will need to "generate" such a row. E.g. something like this would work
SELECT
c.cust,
'PRIOR' AS Range,
( SELECT COUNT(*) FROM table1 t
WHERE t.cust = c.cust AND fordate BETWEEN '2017-01-01' AND '2017-04-13'
) AS count
FROM TABLE(VALUES( 123 )) AS c(cust)
or you could use a LEFT OUTER JOIN
SELECT
c.cust,
'PRIOR' AS Range,
count(t.cust) AS count
FROM TABLE(VALUES( 123 )) AS c(cust)
LEFT OUTER JOIN table1 t
ON t.cust = c.cust
AND t.fordate BETWEEN '2017-01-01' AND '2017-04-13'
GROUP BY
c.cust
I had a similar issue, I wanted to report on number of rows meeting a condition. The following solved it for me;
SELECT Count(*), 'Duplicated Contractor LGA records - post-delete'
FROM (SELECT Company, LGA
FROM detcontractorLGA
GROUP BY Company, LGA
HAVING count(*) > 1
)
;

sql not in and in oporators

HI I am unable to filter materials that belong to only specific list.
Select material
from price
where region='04'
and pricelist ='5'
and pricelist not in ('4','6','7');
I want only those materials which are unique only in pricelist 5 and not in any other pricelists. how can i get this?
You might try something like this (alternately, you could do a self-join, but I think this is just as easy, if not easier, to understand):
SELECT material
FROM price a
WHERE region = '04'
AND pricelist = '5'
AND NOT EXISTS ( SELECT 1 FROM price b
WHERE b.material = a.material
AND b.region = a.region
AND b.pricelist != a.pricelist )
What the above will do will find values of material in region '04' where the pricelist is '5' while excluding those same materials in the same region but on a different price list.
Your current query will only return results where pricelist = 5 -- the not in statement is irrelevant unless it exclude that record. It sounds like you want to return any material which matches on the 5, but doesn't have any other non-5 matches.
One option is to use exist. Here's another option using conditional aggregation with max and case which eliminates the need for multiple queries:
select material
from (
select material,
max(case when pricelist = '5' then 1 else 0 end) haspl5,
max(case when pricelist != '5' then 1 else 0 end) hasothers
from price
where region='04'
group by material
) t
where haspl5 = 1 and hasothers != 1
SQL Fiddle Demo

SQL Nested Select statements with COUNT()

I'll try to describe as best I can, but it's hard for me to wrap my whole head around this problem let alone describe it....
I am trying to select multiple results in one query to display the current status of a database. I have the first column as one type of record, and the second column as a sub-category of the first column. The subcategory is then linked to more records underneath that, distinguished by status, forming several more columns. I need to display every main-category/subcategory combination, and then the count of how many of each sub-status there are beneath that subcategory in the subsequent columns. I've got it so that I can display the unique combinations, but I'm not sure how to nest the select statements so that I can select the count of a completely different table from the main query. My problem lies in that to display the main category and sub category, I can pull from one table, but I need to count from a different table. Any ideas on the matter would be greatly appreciated
Here's what I have. The count statements would be replaced with the count of each status:
SELECT wave_num "WAVE NUMBER",
int_tasktype "INT / TaskType",
COUNT (1) total,
COUNT (1) "LOCKED/DISABLED",
COUNT (1) released,
COUNT (1) "PARTIALLY ASSEMBLED",
COUNT (1) assembled
FROM (SELECT DISTINCT
(t.invn_need_type || ' / ' || s.code_desc) int_tasktype,
t.task_genrtn_ref_nbr wave_num
FROM sys_code s, task_hdr t
WHERE t.task_genrtn_ref_nbr IN
(SELECT ship_wave_nbr
FROM ship_wave_parm
WHERE TRUNC (create_date_time) LIKE SYSDATE - 7)
AND s.code_type = '590'
AND s.rec_type = 'S'
AND s.code_id = t.task_type),
ship_wave_parm swp
GROUP BY wave_num, int_tasktype
ORDER BY wave_num
Image here: http://i.imgur.com/JX334.png
Guessing a bit,both regarding your problem and Oracle (which I've - unfortunately - never used), hopefully it will give you some ideas. Sorry for completely messing up the way you write SQL, SELECT ... FROM (SELECT ... WHERE ... IN (SELECT ...)) simply confuses me, so I have to restructure:
with tmp(int_tasktype, wave_num) as
(select distinct (t.invn_need_type || ' / ' || s.code_desc), t.task_genrtn_ref_nbr
from sys_code s
join task_hdr t
on s.code_id = t.task_type
where s.code_type = '590'
and s.rec_type = 'S'
and exists(select 1 from ship_wave_parm p
where t.task_genrtn_ref_nbr = p.ship_wave_nbr
and trunc(p.create_date_time) = sysdate - 7))
select t.wave_num "WAVE NUMBER", t.int_tasktype "INT / TaskType",
count(*) TOTAL,
sum(case when sst.sub_status = 'LOCKED' then 1 end) "LOCKED/DISABLED",
sum(case when sst.sub_status = 'RELEASED' then 1 end) RELEASED,
sum(case when sst.sub_status = 'PARTIAL' then 1 end) "PARTIALLY ASSEMBLED",
sum(case when sst.sub_status = 'ASSEMBLED' then 1 end) ASSEMBLED
from tmp t
join sub_status_table sst
on t.wave_num = sst.wave_num
group by t.wave_num, t.int_tasktype
order by t.wave_num
As you notice, I don't know anything about the table with the substatuses.
You can use inner join, grouping and count to get your result:
suppose tables are as follow :
cat (1)--->(n) subcat (1)----->(n) subcat_detail.
so the query would be :
select cat.title cat_title ,subcat.title subcat_title ,count(*) as cnt from
cat inner join sub_cat on cat.id=subcat.cat_id
inner join subcat_detail on subcat.ID=am.subcat_detail_id
group by cat.title,subcat.title
Generally when you need different counts, you need to use the CASE statment.
select count(*) as total
, case when field1 = "test' then 1 else 0 end as testcount
, case when field2 = 'yes' then 1 else 0 endas field2count
FROM table1

sql query: subtract from results the corresponding USD, YEN value which has Type='r'

I need help with a query. Consider the following table:
I need to select first the sum of each Code from table. I am doing it with simple sum and group by statement. Then I have to subtract the results from each code sum where type='r'
1) Say for first part of query, we will get 2 rows from SUM (one with total USD and one with total YEN)
2) Now I need to subtract from these results the corresponding USD, YEN value which has Type='r'
I have to do it inside SQL and not a stored procedure.
Why not use a WHERE statement to say WHERE Type != 'r' so that those values never even get added to sum in the first place...
SELECT `Code`, SUM(`Amount`) AS `Total`
FROM `Table`
WHERE `Type` != 'r'
GROUP
BY `Code`;
Something like that.
select code, l.amount - r.amount
from
(select code, sum(amount) as amount from my_table group by code) l
left join (select code, sum(amount) as amount from my_table where type = 'r' group by code) r
on l.code = r.code
You can do this in a single, simple query:
select
code,
sum(case when type = 'r' then (-1 * amount) else amount end) as sum
from
yourtable
group by
code
Basically, you're changing the sign of the rows that have type = 'r', so when you sum all rows for a particular code you'll get the correct answer.
Does it have to be a single query?
I'd say SUM the total, then SUM the subcategory where Type='r', then subtract one from the other.
You could do this in one line of SQL, but I'm pretty sure it would be either joining the table with itself or using a subquery. Either way, it's doing the same amount of work as the above.
Try:
select code,
sum(amount) gross_total,
sum(case when type = 'r' then amount else 0 end) type_r_total,
sum(case when type != 'r' then amount else 0 end) net_total
from yourtable
group by code;
to see the overall totals, type R only totals and non-type R totals for each currency on one row per currency, in a single pass.