Check for multiple columns with Single Value using SELECT query - sql

I have a table fruits. Now in UI, I provide a single field for a search criteria. Using this single Search criteria, i want to search in multiple columns of Fruits Table.
Consider Fruits table contains Columns ID,Desc,Price,Quant,Stock. Here Price,Quant are integers and Stock is a varchar.
I have tried the below query which returns the results, but i am worried about the performance.
Suppose assume user enters 2 in the field provided in UI and clicks on search then query will be as shown below
select ID, Desc, Price, Quant, Stock
from Fruits
where Price = '2'
or Quant = '2'
or stock = '2'
Is this the right way to search for multiple columns of same table? Also will be any effect on performance?

First, you want to be sure that the types are compatible. In all likelihood these values are numbers, so drop the quotes:
select ID, Desc, Price, Quant, Stock
from Fruits f
where Price = 2 or Quant = 2 or stock = 2;
This can more simply be written as:
select ID, Desc, Price, Quant, Stock
from Fruits f
where 2 in (Price, Quant, Stock);
but that will not help performance.
In most databases your query will require a full table scan -- although some databases support a particular type of index scan called a skip scan which can help.
The only way I can think to get around that is to have a separate index on each column:
create index idx_fruits_price on fruits(price);
create index idx_fruits_quant on fruits(quant, price);
create index idx_fruits_stock on fruits(stock, quant, price);
(You'll see why the extra columns are helpful.)
And then use union all:
select ID, Desc, Price, Quant, Stock
from Fruits f
where Price = 2
union all
select ID, Desc, Price, Quant, Stock
from Fruits f
where quant = 2 and price <> 2
union all
select ID, Desc, Price, Quant, Stock
from Fruits f
where stock = 2 and price <> 2 and stock <> 2;
Each of the subqueries can use one of the indexes. Because of the inequalities, the results are exclusive -- assuming the column values are not null. If nulls are allowed, the logic can be adjusted to handle that.

Related

Countif or CASE with multiple conditions

I am trying to figure out the most efficient way to count products being placed in a online cart . I have ranked the first 3 items placed in a cart by purchase time(time they were put in the cart not actual check out time), but now am struggling to figure out a way to count the different combinations of items going into the cart.
Counting the individual ranks is easy enough, but I need to figure out a count for purchasing product 1 first and product 1 second as well as all the combinations possible (5 products total). I only need to count first items in the cart, all combinations of first item in cart to second item in cart, and all combinations of second item in cart to third third item in cart.
SELECT
COUNTIF(product = 'Product1' and rank = 1) as firstpurchase_product1,
COUNTIF((product = 'Product1' and rank = 1) and (product = 'Product1' and rank = 2)) as firstpurchase_product1_secondpurchase_product1,
COUNTIF((product = 'Product1' and rank = 1) and (product = 'Product2' and rank = 2)) as firstpurchase_product1_secondpurchase_product2,
#code would continue for all combinations.
FROM(
customer_info.customer_id as customer_id,
customer_info.session_id as session_id,
customer_info.product_purchased as product,
ROW_NUMBER() OVER (PARTITION BY customer_info.session_id ORDER BY customer_info.purchase_time ASC) AS rank
FROM customer_purchases cp,
WHERE p_date >= "2022-04-12"
)rnk
where rnk.finish_rank in (1,2,3)
This seems like a lot of code, is there a better way to do it? The query is returning 0 for all line except when counting just first purchases, should I be using CASE instead?
Any thoughts or ideas would be appreciated.
Thanks!
Example of input:
Product 1, Product 2, Product 3
Product 1, Product 1, Product 1
Product 4, Product 2, Product 1
Product 3, Product 3, Product 5
Product 4, Product 2, Product 4
--this goes on for hundreds of lines
Output:
Count Product 1 in first column
Count Product 2 in first column
#continue for all 5
Count of customers who put product 1 in cart first AND product 1 in cart
second
Count of customers who put product 1 in cart first AND product 2 in cart second
###continue with all combinations with product 1
Count of customers who put product 2 in cart first and product 1 in cart second
Count of customers who put product 2 in the cart first and product 2 in the cart second
###continue with all combinations of product 2,3,4, and 5
It seems to me that you want to GROUP BY a set of columns (item1, item2, item3) and produce a count of the number of times each combination occurs.
Possibly (it's a little unclear from your wording - a well-formatted table showing example raw data and desired results for that example would be helpful), you want to know an overall count for values of item1 regardless of the other items. This can be achieved via GROUP BY ROLLUP(item1, item2, item3).
So, our aim is to get an unaggregated table with those columns, so that we can aggregate it as described!
You have a long-format table (customer ID, session ID, product, rank) and we want a wide-format table with a column for each value of rank. This is a PIVOT operation:
WITH rnk AS (
SELECT
customer_id,
session_id,
product_purchased AS product,
ROW_NUMBER() OVER (PARTITION BY session_id ORDER BY purchase_time ASC) AS rank
FROM customer_info
WHERE p_date >= "2022-04-12"
QUALIFY rank IN (1,2,3)
),
pivoted AS (
SELECT *
FROM rnk PIVOT(
ANY_VALUE(product) AS item FOR rank in (1,2,3)
)
)
SELECT
item_1,
item_2,
item_3,
COUNT(*) AS N
FROM
pivoted
GROUP BY
ROLLUP(item_1, item_2, item_3)
Does that get you what you want?
A couple of features to note:
I use common table expressions (WITH) to make this more readable
QUALIFY is a filter clause to apply to the output of a window clause
Pivoting requires an aggregation function because in general there could be many records with the same value of session, product, and rank. Here we know there will be one record only, so it's safe to use ANY_VALUE (which 'aggregates' by non-deterministically choosing one of the values).
Just to prevent confusion: ROLLUP will give you something like 'Product A', NULL, NULL for some of its records - this doesn't mean items 2 and 3 don't exist, it's just how it signals those records that group only by item 1 and aggregate over all values of the other items.

Is it possible to aggregate the results from different rows into just one, along with the count?

So I've got a small DB that has like subsections that come under a single section. Unfortunately, the DB doesn't have a "section" column and just the subsections and they have a "Inventory" column that has either "Computer" or "Laptop" in it. I've made a query that at the very least provides me with the total count of each of these "Inventory" column against each subsection.
However, I'm trying to combine the subsections into a single row and the total count of those subsections alongside it as well. Example of what I'm trying to say:
subsections
inventory
a_subsec1
comp
a_subsec1
comp
a_subsec2
lap
a_subsec2
comp
a_subsec3
lap
a_subsec3
comp
What I'm currently getting:
d_sub
inv_count_comp
a_subsec1
2
a_subsec2
1
a_subsec3
1
What I WANT to get:
D_SUB
total_comp_count
a_sec
4
Here's the query that I'm currently running to get that second table:
SELECT DISTINCT "subsections", COUNT("inventory") FROM mytable WHERE "inventory" = 'comp' GROUP BY "subsections" ORDER BY "subsections" ASC
Thank you.
substring the column then you can treat all the row as same subsection.
with tb as(
select 'a_subsec1' sec,'comp' inv
union all
select 'a_subsec1' sec,'comp' inv
union all
select 'a_subsec2' sec,'lap' inv
union all
select 'a_subsec2' sec,'comp' inv
union all
select 'a_subsec3' sec,'lap' inv
union all
select 'a_subsec3' sec,'comp' inv
)
select msec,sum(inv_comp) total from(
select concat(substr(sec,1,1),'_sec') as msec,
case when inv='comp' then 1 else 0 end as inv_comp,
tb.*
from tb) z
group by msec
this query might not be the one you want without some modify but main idea is same.
db<>fiddle

Most efficient way to implement this logic in Oracle

The problem is as follows. Let there be two types of orders, VE and VC orders (VE orders have priority over VC orders). And two types of priorities HIGH and LOW. Every order is identified by an ORDER_ID, then labeled with an order type and lastly a priority. It happens that over time orders can improve their type, priority, or both, resulting in several new entries with duplicate order id's. The task is to label the state with the highest priority for each order with 1 and the rest with 0's. How would you attempt to do this considering that the ORDERS table is sufficiently big and that in some cases some rows would have to be re-labeled.
Example input:
Example output:
"How would you attempt to do this considering that the ORDERS table is
sufficiently big "
Well, first of all I wouldn't query all the rows in a "sufficiently big" table. That's why Nature gave us the WHERE clause.
So, given some form of filtering, the remaining logic is:
select order_id
, order_type
, priority
, case when rn = 1 then 1 else 0 end as temp_label
from
( select order_id
, order_type
, priority
, row_number() over ( partition by order_id
order by decode(order_type, 'VE', 1, 2)
, decode(priority, 'HIGH', 1, 2)
) as rn
from your_table
where whatever = 'BLAH' -- your criteria go here
)

Need to sum two columns from two tables, separately, based on products in table 3

I have three tables.
Table 1: Product mapping table,
Table 2: FY12 Sales Numbers,
Table 3: FY13 Sales Numbers.
Basically, I want the end result to be three columns: Product, FY12 Qty, FY13 Qty.
Right now I join the Product Mapping table to the Two Sales tables. If I do this one sales table at a time I get the right numbers. As soon as I try to get the sum from the other table the numbers are all off.
Here is the code that works for getting quantity from one table, but I can't figure out how to get another column in the result that sums the same product groupings from another table.
select PRODUCT_MAPPING.PRODUCT_FAMILY as PRODUCT_FAMILY,
PRODUCT_MAPPING.PRODUCT_CONFIG as PRODUCT_CONFIG,
sum(CURRENTWEEK_PIPE.FY13_QUANTITY) as FY13_QUANTITY
from PRODUCT_MAPPING PRODUCT_MAPPING,
CURRENTWEEK_PIPE CURRENTWEEK_PIPE
where CURRENTWEEK_PIPE.PRODUCT_ITEM=PRODUCT_MAPPING.PRODUCT_ITEM
and PRODUCT_MAPPING.PRODUCT_CONFIG is not null
group by PRODUCT_MAPPING.PRODUCT_FAMILY, PRODUCT_MAPPING.PRODUCT_CONFIG
order by PRODUCT_MAPPING.PRODUCT_FAMILY ASC, PRODUCT_MAPPING.PRODUCT_CONFIG ASC
do you try to use subqueries?
SELECT sum(CURRENTWEEK_PIPE.FY13_QUANTITY), sum(CURRENTWEEK_PIPE.FY12_QUANTITY) From .....
select PRODUCT_MAPPING.PRODUCT_FAMILY as PRODUCT_FAMILY,
PRODUCT_MAPPING.PRODUCT_CONFIG as PRODUCT_CONFIG,
(SELECT sum(CURRENTWEEK_PIPE.FY13_QUANTITY), sum(CURRENTWEEK_PIPE.FY12_QUANTITY) From ....... ) as FY13_QUANTITY from PRODUCT_MAPPING PRODUCT_MAPPING,
CURRENTWEEK_PIPE CURRENTWEEK_PIPE where CURRENTWEEK_PIPE.PRODUCT_ITEM=PRODUCT_MAPPING.PRODUCT_ITEM
and PRODUCT_MAPPING.PRODUCT_CONFIG is not null group by PRODUCT_MAPPING.PRODUCT_FAMILY, PRODUCT_MAPPING.PRODUCT_CONFIG order
by PRODUCT_MAPPING.PRODUCT_FAMILY ASC, PRODUCT_MAPPING.PRODUCT_CONFIG
ASC

sub query returned more than 1 value

I have to write a query which returns the price of books greater than the average price for books of similar type. So, I did this using the below query:
select title
from titles
where price >
(
select avg(price)
from titles
group by type
)
However it throws this error:
subquery returned more than 1 value
It is understandable that > cannot be used for a list of values. But I wanted to know the way I can solve this. Please let me know the query I need to use. The DB is pubs
titles table:
title_id , title, type, price, advance, notes, sales
so I need to get the title with price > average (price) of similar types
The key is to use the type from the main query to filter the type in the subquery.
SELECT t.title
FROM titles t
WHERE t.price > (SELECT AVG(t2.price)
FROM titles t2
WHERE t2.type = t.type)
You have more than one type, so each type is returning an average.
You can look into the SOME|ANY or ALL operators to look at the list of items
If you were looking for the titles whose prices are higher than all of the average types, An example of this would be:
SELECT title
FROM titles
WHERE price > ALL
(
SELECT AVG(price)
FROM titles
GROUP BY type
)
You could similarly change ALL to SOME or ANY to suit your needs.
select title
from titles
where price >
(select avg(price) from titles)
The above query assumes that you want the average of all title prices to compare against. This will return a scalar value and allow your query to succeed.
You need to link types from subquery and main query, example:
select
a.title
from
titles a
where
a.price > ( select avg(b.price) from titles b where a.type = b.type group by b.type)