SQLite: Divide value from one column based on criteria from other columns - sql

I have a table in SQLite3 with the following structure:
Date Category Value
------------ -------------- -------------
20160101 A 5
20160101 B 3
20160102 A 4
20160102 B 2
20160103 A 7
20160103 B 3
20160104 A 8
20160104 B 1
My goal is to select values from the table so that for each date I divide the value of category A with the value of category B. I have exactly one value for each category for every date. I.e. the goal is to select two columns with these values:
Date NewValue(A/B)
------------ --------------
20160101 1.6667
20160102 2
20160103 2.3333
20160104 8
I have tried to solve this by creating a temporary table, but I get wrong values.

You can do this using conditional aggregation or a join:
select t.date, ta.value / tb.value
from t ta join
t tb
on ta.date = tb.date and ta.category = 'A' and tb.category = 'B';
One caveat: SQLite does integer division. So, if the values are integers, you should use something like:
select t.date, ta.value * 1.0 / tb.value

Related

Select rows from a particular row to latest row if that particular row type exist

I want to achieve these two requirements using a single query. Currently I'm using 2 queries in the program and use C# to do the process part something like this.
Pseudocode
select top 1 id from table where type=b
if result.row.count > 0 {var typeBid = row["id"]}
select * from table where id >= {typeBid}
else
select * from table
Req1: If there is records exist with type=b, Result should be latest row with type=b and all other rows added after.
Table
--------------------
id type date
--------------------
1 b 2021-10-15
2 a 2021-11-16
3 b 2021-11-19
4 a 2021-12-02
5 c 2021-12-12
6 a 2021-12-16
Result
--------------------
id type date
--------------------
3 b 2021-11-19
4 a 2021-12-02
5 c 2021-12-12
6 a 2021-12-16
Req2: There is NO record exist with type=b. Query should select all the records in the table
Table
---------------------
id type date
---------------------
1 a 2021-10-15
2 a 2021-11-16
3 a 2021-11-19
4 a 2021-12-02
5 c 2021-12-12
6 a 2021-12-16
Result
--------------------
id type date
--------------------
1 a 2021-10-15
2 a 2021-11-16
3 a 2021-11-19
4 a 2021-12-02
5 c 2021-12-12
6 a 2021-12-16
with max_b_date as (select max(date) as date
from table1 where type = 'b')
select t1.*
from table1 t1
cross join max_b_date
where t1.date >= max_b_date.date
or max_b_date.date is null
(table is a SQL reserved word, https://en.wikipedia.org/wiki/SQL_reserved_words, so I used table1 as table name instead.)
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=bd05543a9712e27f01528708f10b209f
Please try this(It's somewhat deep but might you exact looking for)
select ab.* from
((select top 1 id, type, date from test where type = 'b' order by id desc)
union
select * from test where type != 'b') as ab
where ab.id >= (select COALESCE((select top 1 id from test where type = 'b' order by id desc), 0))
order by ab.id;
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=739eb6bfee787e5079e616bbf4e933b1
Looks Like you can use an OR condition here
SELECT
*
FROM
(
SELECT
*,
BCount = COUNT(CASE type WHEN 'B' THEN 1 ELSE NULL END)-- to get the Count of Records with Type b.
FROM Table
)Q
WHERE
(
BCount > 0 AND id >= (select top 1 id from table where type=b)-- if there are Row's with Type b then select Req#1
)
OR
(
BCount = 0 -- if THere are no rows with Type B select All
)

how can i get an accurate count based on max date when joining 3 tables when one of the join fields is many to 1 in oracle?

So, I have 3 tables that I am attempting to get counts for based on a groupid, and a task code. There are a few issues I am having as some of the relationships are many to one, which I think is somehow inflating my counts. I will list my 3 tables with the pertinent attributes.
task_table contains:
task_code - would like to get the counts of each one in a group id, would like to use the latest instance basedon event date.
sol_id -used to join to worktable; many sol_id to one m_id is possible
edate -need to use to get one record
cur_id - where cur_id = 1 in the where clause
worktable contains:
sol_id - used to join to task_table
m_id - used to join to grouptable
grouptable contains:
m_id
groupid- used to group the task_code to get count
I'd like the end result to look like:
group_id task_count task
5555 45 A
5555 4 N
5624 67 A
5624 23 O
5624 42 X
I have been attempting to run a number of queries, but the counts I am getting back do not look correct. I am concerned that it is somehow returning more than one instance of the m_id somehow? Here is the query in question:
select c.groupid, count(c.groupid) group_count, a.task_code from task_table a
join worktable b
on a.sol_id = b.sol_id
join grouptable c
on b.m_id= c.m_id
where a.cur_id = 1 and a.task_code is not null
group by c.groupid, a.task_code;
If I add 'edate = (select max(edate) from task_table)' in the where clause, it returns an empty table.
I am unsure how to incorporate edate to get only the newest record that fits the criteria in the where clause. The reason I think I want to use this is because there could be more than one sol_id that is associated with a m_id, so i'd just like to include only the newest record with a cur_id in the count. Thank you for your time.
sample data
task_table
task_code sol_id edate cur_id
A 23 6/7/09 1
A 24 6/4/09 1
A 23 6/10/09 0
B 45 6/2/09 1
B 42 6/3/09 1
C 34 10/8/10 0
C 83 9/10/09 1
work table
sol_id m_id
23 1234
24 1234
45 1832
42 1343
83 7623
group table
m_id group_id
1234 A76
1832 Y23
1343 A76
7623 Y23
looking at these tables, the result should look like the following
group_id task_count task
A76 2 A
Y23 1 C
( A76 should only count sol_id 23 and 42)
( Y23 should only count sol_id 83)
So, there's a conflict in your requested data result. According to your own sample, A76 should have a task_count of 2: sol_id 23, which has Task A, and sol_id 42, which has Task B. It's not possible to have it return a row like you have at your example result table because it would need to group by TASK_CODE, which means losing the COUNT(task_code). Can't have it both ways.
In order to obtain only the most recent edate, I did a separate calculation to location that max(edate) by task_code, then joined it back to obtain the sol_id. If this isn't accurate for your data set, you'll need to determine another way of obtaining max(edate). This works for your sample set.
with recentTasks as (
select task_code, max(edate) as recentDate
from task_table m
where cur_id = 1
and task_code is not null
group by task_code
), recentTaskWithSols as (
select m.task_code, m.recentDate as edate, t.sol_id
from recentTasks m
join task_table t on m.task_code = t.task_code AND m.recentDate = t.edate
where t.cur_id = 1
)
select c.group_id,
count(a.sol_id) task_count
from group_table c
join work_table b on c.m_id = b.m_id
join recentTaskWithSols a on b.sol_id = a.sol_id
group by c.group_id;
gives the result:
+------------------------+
| GROUP_ID | TASK_COUNT |
+------------------------+
| A76 | 2 |
| Y23 | 1 |
+-----------+------------+
Demo here.

Group by in SQL returning error: Selected non-aggregate values must be part of the associated group

I have a table that looks like this:
date store flag
1 5/4/2018 a 1
2 5/4/2018 a 1
3 5/3/2018 b 1
4 5/3/2018 b 0
5 5/2/2018 a 1
6 5/2/2018 b 0
I want to group by date and store and sum the number of flags
i.e. table_a below:
date store total_flag
1 5/4/2018 a 2
3 5/3/2018 b 1
4 5/2/2018 a 1
5 5/2/2018 b 0
This is what I'm trying:
create multiset volatile table flag_summary as (
sel table_a.*, SUM(table_a.flag) as total_flag
group by date, store
)
with data primary index (date, store) on commit preserve rows;
The above gives me an error, "CREATE TABLE Failed. [3504] Selected non-aggregate values must be part of the associated group.
You are selecting all of tableA (including the flag). You should just be pulling the date and the store since you want the sum of the flag.
SELECT date, store, SUM(flag)
FROM tableA
GROUP BY date, store

trying to get Statistics for data based on another parameter

Struggling again on statistics on data based on other sets of data.
I have a list of customers. like the following:
CustomerID Value Date
1 3 01/01/2017
2 2 01/02/2017
3 1 01/02/2017
1 5 01/04/2017
1 6 01/04/2017
2 1 01/04/2017
2 2 01/04/2017
I want to get an average for a date range for Customer 1 on the days where customer 2 also has values. Does anyone have any thoughts?
example
Select avg(value)
from Table where customerid=1
and (customer 2 values are not blank)
and date between '01/01/2017' and '01/31/2017'
I am using SQL Server Express 2012.
Another Option
Select AvgValue = Avg(Value+0.0) -- Remove +0.0 if you want an INT
From YourTable
Where CustomerID = 1
and Date in (Select Distinct Date from YourTable Where CustomerID=2)
Returns
AvgValue
5.500000
You can select the dates using exists or in and then calculate the average:
select avg(value)
from datatbl t
where customerid = 1 and
exists (select 1 from datatbl t2 where t2.customerId = 2 and t2.date = t.date);
If you want the average per date, then include group by date.

Microsoft SQL - Counting total of matching values in other table

I have a SQL data scructure like this.
Table 1
http://pbrd.co/1x6TAl3
Table 2
http://pbrd.co/1x6TIRw
I'm trying to count the number of times each item_num has been sold based on the item_qty value in the second table.
Each item_num can appear multiple times in the second table.
I need a way to add the total item_qty for each associated item_num and output it to show how many times an item has been sold.
The correct output ordering by total quantity sold in descending order should look like this.
item_num: 4 7 6
qty_sold: 11 5 4
Try this:
SELECT
a.item_num
, SUM(b.item_qty) as "qty_sold"
FROM
Table1 a
LEFT JOIN
Table2 b
ON a.item_num = b.item_num
GROUP BY
a.item_num
ORDER BY
qty_sold DESC
SELECT A.Item_num , A.Item_name , sum(B.Item_Qty) from Table1 as A inner join Table2 as B
on A.Item_num=B.Item_num
group by A.Item_num , A.Item_name
result:
item_num item_name Item_qty
1 A 1
2 B 1
4 D 11
6 F 4
7 G 5