Getting all items without open end date - mysql

I need to solve following problem using (My)SQL, given is this example table:
id | item | start | end
1 | 100 | 2015-01-01 | 2015-01-14
2 | 100 | 2015-01-01 | NULL
3 | 101 | 2015-03-01 | 2015-04-15
4 | 101 | 2015-04-17 | 2015-04-22
5 | 101 | 2015-04-27 | 2015-05-11
I need a query that gives me all items where there is no open end date. So from the above I'd expect to get 101.
I tried it with GROUP and some sub-selects but didn't show up like I expected. Any help on this?

You can do this using group by and having:
select item
from example
group by item
having count(end) = count(*);
count() with a column names counts the number of non-NULL values. If this is equal to the number of rows, then no values are NULL.
You could also use:
having sum(end is null) = 0
EDIT:
I should add that the following might be faster, assuming you have the right indexes and a table for items:
select i.item
from items i
where not exists (select 1
from example e
where i.item = e.item and e.end is null
);
For performance, you want an index on example(item, end).

Related

SQL Query with all data from lest column and fill blank with previous row value

After searching a lot on this forum and the web, i have an issue that i cannot solve without your help.
The requirement look simple but not the code :-(
Basically i need to make a report on cumulative sales by product by week.
I have a table with the calendar (including all the weeks) and a view which gives me all the cumulative values by product and sorted by week. What i need the query to do is to give me all the weeks for each products and then add in a column the cumulative values from the view. if this value does not exist, then it should give me the last know record.
Can you help?
Thanks,
The principal is establish all the weeks that a product could have had sales , sum grouping by week, add the missing weeks and use the sum over window function to get a cumulative sum
DROP TABLE IF EXISTS T;
CREATE TABLE T
(PROD INT, DT DATE, AMOUNT INT);
INSERT INTO T VALUES
(1,'2022-01-01', 10),(1,'2022-01-01', 10),(1,'2022-01-20', 10),
(2,'2022-01-10', 10);
WITH CTE AS
(SELECT MIN(YEARWEEK(DT)) MINYW, MAX(YEARWEEK(DT)) MAXYW FROM T),
CTE1 AS
(SELECT DISTINCT YEARWEEK(DTE) YW ,PROD
FROM DATES
JOIN CTE ON YEARWEEK(DTE) BETWEEN MINYW AND MAXYW
CROSS JOIN (SELECT DISTINCT PROD FROM T) C
)
SELECT CTE1.YW,CTE1.PROD
,SUMAMT,
SUM(SUMAMT) OVER(PARTITION BY CTE1.PROD ORDER BY CTE1.YW) CUMSUM
FROM CTE1
LEFT JOIN
(SELECT YEARWEEK(DT) YW,PROD ,SUM(AMOUNT) SUMAMT
FROM T
GROUP BY YEARWEEK(DT),PROD
) S ON S.PROD = CTE1.PROD AND S.YW = CTE1.YW
ORDER BY CTE1.PROD,CTE1.YW
;
+--------+------+--------+--------+
| YW | PROD | SUMAMT | CUMSUM |
+--------+------+--------+--------+
| 202152 | 1 | 20 | 20 |
| 202201 | 1 | NULL | 20 |
| 202202 | 1 | NULL | 20 |
| 202203 | 1 | 10 | 30 |
| 202152 | 2 | NULL | NULL |
| 202201 | 2 | NULL | NULL |
| 202202 | 2 | 10 | 10 |
| 202203 | 2 | NULL | 10 |
+--------+------+--------+--------+
8 rows in set (0.021 sec)
Your calendar date may be slightly different to mine but you should get the general idea.

Selecting items that have same values in the same column

I am facing a conundrum; not sure why -- is it because this late, or I am just stuck. My goal is to create a filter on the webpage, so I am trying to figure this out.
I have a list of products that I store with filters in the reference table product_filter.
The structure:
id | product_id | filter1_id | filter2_id
1 | 1 | 2 | 1 <---
2 | 1 | 4 | 3
3 | 1 | 5 | 1
4 | 2 | 2 | 1 <---
5 | 2 | 3 | 1
6 | 3 | 2 | 1 <---
7 | 3 | 3 | 4
I need to submit a list of products (for example 1,2,3) and get only those filter combinations, that are the same for all selected product id's. So the result needs to be
filter1_id | filter2_id
2 | 1
My problem is that my products might vary and I can't do a ton of self inner joins... so I am stuck... Any advise?
Here is one approach that you could try:
select filter1_id, filter2_id
from product_filter
group by filter1_id, filter2_id
having count(*)=(
select count(distinct product_id)
from product_filter
)
This will only return a list when a combination of filter1_id and filter2_id exists for every product_id. (Fiddle here.) Is that what you are after? Do you don't mention what should be returned if there isn't any combination that exists for all of the given product_id's - an empty result set?
It's not a self-join (or even a ton of them ;) ) but it will still be fairly expensive I imagine.

How does this matrix multiply work in SQL?

Full disclosure, I'm a noob at SQL
Given two sparce matrices A and B, defined as:
A(row_number, column_number, value) and B(row_number, column_number, value)
I don't understand how this query represents the multiplication of the two matrices:
SELECT A.row_number, B.column_number, SUM(A.value * B.value)
FROM A, B
WHERE A.column_number = B.row_number
GROUP BY A.row_number, B.column_number
My confusion lies in the SUM syntax and the GROUP BY / SELECT syntax
So for my GROUP BY / SELECT confusion, I don't understand why the expressions
A.row_number and B.column_number are necessary after the SELECT statement
Why do we have to specify that when we're already using SELECT and WHERE ? To me that seems like we're saying we want to SELECT using those expressions (A.row_number and B.column_number) even though we're given back a table from WHERE already. Would it not make more sense to just say SELECT * ? I'm assuming that GROUP BY just requires you to type out the expressions it uses in the SELECT statement, but I don't know for sure.
For the SUM, I just want to clarify, the SUM is only using the A.value and the B.value from whatever is returned by the WHERE correct? Otherwise, you would be multiplying all A.value with all B.value.
Clarifying either of these would be immensely helpful. Thank you!
create table A
( column_number int,
row_number int,
value int
);
create table B
( column_number int,
row_number int,
value int
);
insert A (column_number,row_number,value) values (1,1,1),(1,2,2),(2,1,3),(2,2,4);
insert B (column_number,row_number,value) values (1,1,10),(1,2,20),(2,1,30),(2,2,40);
Data with your old style (non explicit) join without aggregage or group by:
SELECT A.row_number as Ar, B.column_number as Bc,
A.value as Av,B.value as Bv,A.value*B.value as product
FROM A, B
WHERE A.column_number = B.row_number
+------+------+------+------+---------+
| Ar | Bc | Av | Bv | product |
+------+------+------+------+---------+
| 1 | 1 | 1 | 10 | 10 |
| 2 | 1 | 2 | 10 | 20 |
| 1 | 1 | 3 | 20 | 60 |
| 2 | 1 | 4 | 20 | 80 |
| 1 | 2 | 1 | 30 | 30 |
| 2 | 2 | 2 | 30 | 60 |
| 1 | 2 | 3 | 40 | 120 |
| 2 | 2 | 4 | 40 | 160 |
+------+------+------+------+---------+
Seeing the above, the below gets a little more clarity:
SELECT A.row_number, B.column_number,sum(A.value * B.value) as theSum
FROM A, B
WHERE A.column_number = B.row_number
GROUP BY A.row_number, B.column_number
+------------+---------------+--------+
| row_number | column_number | theSum |
+------------+---------------+--------+
| 1 | 1 | 70 |
| 1 | 2 | 150 |
| 2 | 1 | 100 |
| 2 | 2 | 220 |
+------------+---------------+--------+
Giving table name after SELECT will identify which table to refer to. Mainly useful in the case where both tables have same column names.
GROUP BY will aggregate the data and display one record per grouped-by value. That is, in your case, you'll end up with only one record per row-column combination.
By definition multiplication of two matrices A(n,m) and B(m,p) produces a matrix C(n,p).
So the SQL for multiplication should return same data structure as was used for storage of A and B, which is three columns:
row_number
column_number
value
, with one value per (row, column) combination.
This is why you need first two in the group by clause.
WHERE clause is independent from SELECT. First is responsible for getting the right records, second for getting the right columns.

SQL: Keep subquery order in outer query

I am having issues trying to combine DISTINCT & ORDER BY. I have a Users table with the following attributes id, name & I have a Purchases table with the following attributes id,user_id,date_purchased,returned
I want to retrieve all unique Users that have a returned Purchase sorted by date_purchased.
Here is some sample data
Users
id | name
---+-----------
1 | Bob
2 | John
3 | Bill
4 | Frank
5 | Fred
6 | Al
Purchases
id | user_id | startdate | returned
-----+------------------+------------+---------------
100 | 1 | 2015-02-06 | true
101 | 1 | 2015-01-06 | true
102 | 1 | 2015-02-05 | false
103 | 2 | 2015-02-05 | false
104 | 2 | 2015-02-05 | false
105 | 3 | 2015-01-05 | true
106 | 3 | 2015-02-04 | true
107 | 4 | 2015-01-07 | true
108 | 5 | 2015-02-05 | false
109 | 6 | 2015-02-07 | false
110 | 6 | 2015-01-05 | true
The result should be the following user id's 1,3,4,6
Here is the query I wrote
SELECT DISTINCT (id) FROM (
SELECT users.id as id, purchases.startdate FROM
users INNER JOIN purchases on users.id=purchases.id
WHERE returned=true
ORDER BY startdate )
This query correctly returns the results; however it is in the incorrect order. Reading other answers I found that you can't maintain the subquery ordering. I tried to move the ordering to the outer query; however, startdate would also need to be present in the select query & that is not what I want
Just remove the subquery and use GROUP BY:
SELECT u.id as id
FROM users u INNER JOIN
purchases p
on u.id = p.id
WHERE returned = true
GROUP BY u.id
ORDER BY MIN(startdate);
You can only rely on the result set being in a particular order when you use ORDER BY for the outermost SELECT. There is no guarantee of ordering in any other case.
As a note: ordering usually does work with subquery (sadly, because many people look at the results from some queries and generalize to all of them). The problem in this case is the distinct. It rearranges the data (i.e. sorts it) to remove duplicates.
Gordon's script gives you the data you want, but to answer your question of how to maintain a subquery's order, you can pull the column you want to order by out of the subquery and then order by it.
SELECT DISTINCT (id), innerTable.startdate FROM (
SELECT users.id as id, purchases.startdate FROM
users INNER JOIN purchases on users.id=purchases.id
WHERE returned=true) as innerTable
ORDER BY innerTable.startdate

MySQL query: select records with highest value in group

I have a MySQL table like this.
| season_id | round_1 | names | score_round_1
| 5 | 10 | John1 | 5
| 5 | 10 | John2 | 3
| 5 | 11 | John3 | 2
| 5 | 11 | John4 | 5
I want to select the records with highest score_round_1 in each round_1(10,11) group .
In this case the first and last rows would be selected.
I tried using the GROUP BY round_1 but that only returns the first row from the two.
Any advice?
Zolka
This is simple
select max(score_round_1),
name
from score
group by round_1
SELECT *
FROM table p1
WHERE score_round_1 = (
SELECT MAX( p2.score_round_1 )
FROM table p2
WHERE p1.round_1 = p2.round_1 ) ANDround_1 !=0
Use aggregate function MAX
SELECT names, MAX(score_round_1) GROUP BY round_1