table a shows user current selecting item (contains: selected_date, item_id)
which is added after user selected a item
table b shows user unselected history (contains: selected_date, unselected_date, item_id)
which is added after user unselected a item
I want to show the selected count changes of all items between date r and y
just like:
item_id | change
1 | +1
2 | -3
3 | +10
tables:
create table a (
user_id int,
item_id int ,
selected_date date,
)
create table b (
item_id int,
selected_date date,
unselected_date date,
primary key(item_id, selected_date)
);
sample data:
a:
+-------+--------------+
|item_id|selected_date |
+-------+--------------+
| 48|2022-03-17 |
| 49|2022-03-17 |
+-------+--------------+
b:
+-------+--------------+---------------+
|item_id|selected_date |unselected_date|
+-------+--------------+---------------+
| 47|2022-03-14 |2022-03-17 |
| 48|2020-03-11 |2022-03-12 |
| 49|2021-03-17 |2022-03-14 |
+-------+--------------+---------------+
Output:
if r = 2022-03-15, y = 2022-03-17
+-------+------+
|item_id|change|
+-------+------+
| 47|-1 |
| 48|+2 |
| 49|+1 |
+-------+------+
Ok, I should explain my problem more detail.
I need to union two query of table a and b into:
select (date), (sum of changes)
a means changes +1
and b means changes -1
Therefore, if day y has 4 rows of a and 2 rows of b. (selected_date = y)
It should get:
+----+-------+
|date|changes|
+----+-------+
| y|+2 |
+----+-------+
My solution
As jiwopene said, I mix table a and b into one table.
It has selected_date and nullable unselected_date.
Finally, get the sum of changes using case
select date, sum(num) from (
select a.selected_date as date,
case
when a.unselected_date is null then 1
else -1
end as num
from a
) as sq
group by date;
Related
I want to rows according to same column value.
Suppose this is a table
id name topic
1 A t
2 B a
3 c t
4 d b
5 e b
6 f a
I want result something like this.
id name topic
1 A t
3 c t
2 B a
6 f a
4 d b
5 e b
As you can see these are not order by topic neither by id, it sort about that topic which come first if t come first sort t first, one second a come then sort according to a then b.
if you apply ORDER BY topic it sort a b t or in DESC t b a but required result is t a b
Any suggestion ?
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,topic CHAR(1) NOT NULL
);
INSERT INTO my_table VALUES
(1,'t'),
(2,'a'),
(3,'t'),
(4,'b'),
(5,'b'),
(6,'a');
SELECT x.*
FROM my_table x
JOIN
( SELECT topic, MIN(id) id FROM my_table GROUP BY topic ) y
ON y.topic = x.topic
ORDER
BY y.id,x.id;
+----+-------+
| id | topic |
+----+-------+
| 1 | t |
| 3 | t |
| 2 | a |
| 6 | a |
| 4 | b |
| 5 | b |
+----+-------+
You can use CASE expression in ORDER BY.
Query
select * from `your_table_name`
order by
case `topic`
when 't' then 1
when 'a' then 2
when 'b' then 3
else 4 end
, `name`;
I have the following table:
mysql> select * from foo;
| id | value | bar |
+----+-------+------+
| 1 | 2 | 3 |
| 2 | 0 | 3 |
| 1 | 1 | 5 |
I want to select the tuple with the maximum value for each id. However, when max(value) is 0, I don't get a result.
mysql> select id,max(value),bar from foo group by id having max(value);
| id | max(value) | bar |
+----+------------+------+
| 1 | 2 | 3 |
Is this supposed to behave like that and if so, why?
HAVING cannot be used in any way to pick a record out of a group of records as defined by the fields used in the GROUP BY clause. It is rather applied to the group as a whole.
So, in your case, you have to do a self-join to get the rest of the table fields:
select t1.id, t1.value, t1...
from foo as t1
join (
select id, max(value) as max_value
from foo
group by id
) as t2 on t1.id = t2.id and t1.value = t2.max_value
IMHO you can get MAX couple by multiplying (id x value).
create table foo(id int, value int);
insert into foo values
(2,0),
(1,0),
(2,1),
(3,0),
(2,2);
select id, value
from foo
order by (id * value) desc
limit 1;
id | value
2 | 2
drop table foo;
I have a single SQL table that contains multiple entries for each customerID (some customerID's only have one entry which I want to keep). I need to remove all but the most recent entry per customerID, using the invoiceDate field as my marker.
So I need to go from this:
+------------+-------------+-----------+
| customerID | invoiceDate | invoiceID |
+------------+-------------+-----------+
| 1 | 1393995600 | xx |
| 1 | 1373688000 | xx |
| 1 | 1365220800 | xx |
| 2 | 1265220800 | xx |
| 2 | 1173688000 | xx |
| 3 | 1325330800 | xx |
+------------+-------------+-----------+
To this:
+------------+-------------+-----------+
| customerID | invoiceDate | invoiceID |
+------------+-------------+-----------+
| 1 | 1393995600 | xx |
| 2 | 1265220800 | xx |
| 3 | 1325330800 | xx |
+------------+-------------+-----------+
Any guidance would be greatly appreciated!
Write a query to select all the rows you want to delete:
SELECT * FROM t
WHERE invoiceDate NOT IN (
SELECT MAX(invoiceDate)
-- "FROM t AS t2" isn't supported by MySQL, see http://stackoverflow.com/a/14302701/227576
FROM (SELECT * FROM t) AS t2
WHERE t2.customerId = t.customerId
GROUP BY t2.customerId
)
This may take a long time on a big database.
If you're satisfied, change the query to a DELETE statement:
DELETE FROM t
WHERE invoiceDate NOT IN (
SELECT MAX(invoiceDate)
-- "FROM t AS t2" isn't supported by MySQL, see http://stackoverflow.com/a/14302701/227576
FROM (SELECT * FROM t) AS t2
WHERE t2.customerId = t.customerId
GROUP BY t2.customerId
)
See http://sqlfiddle.com/#!9/6e031/1
If you have multiple rows whose date is the most recent for the same customer, you would have to look for duplicates and decide which one you want to keep yourself. For instance, look at customerId 2 on the SQL fiddle link above.
Try out this one
with todelete as
(
select
CustomerId, InvoiceId, InvoiceDate, Row_Number() over (partition by CustomerId order by InvoiceDate desc) as Count
from DeleteDuplicate
)
delete from todelete
where count > 1
Let us asume that the table name is transaction_table.
create table test1 AS
select * from (
select * from transaction_table order by customerID, invoiceDate desc) temp
group by customerID
You will have the output data in test1 table.
delete from ex_4 where
rowid in
(select rowid
from ex_4 a
where to_date(invoicedate,'DDMMYYYY') = (select max(to_date(invoicedate,'DDMMYYYY')) from ex_4 b where a.customerid != b.customerid))
This is how it will be done in oracle.This query will delete all but most recently added row.Looking at your table structure i am assuming that the invoicedate column is varchar2 type so converting it to date used to_date function here
I'm trying to calculate row differences (like MySQL difference between two rows of a SELECT Statement) over a grouped result set:
create table test (i int not null auto_increment, a int, b int, primary key (i));
insert into test (a,b) value (1,1),(1,2),(2,4),(2,8);
Gives
| a | b
---------
| 1 | 1
| 1 | 2
| 2 | 4
| 2 | 8
This is the simple SQL with group and max(group) result columns:
select
data.a,
max(data.b)
from
(
select a, b
from test
order by i
) as data
group by a
order by a
The obvious result is
| a | max(data.b)
-----------------
| 1 | 2
| 2 | 8
Where I'm failing is when I want to calculate the row-by-row differences on the grouped column:
set #c:=0;
select
data.a,
max(data.b),
#c:=max(data.b)-#c
from
(
select a, b
from test
order by i
) as data
group by a
order by a
Still gives:
| a | max(data.b) | #c:=max(data.b)-#c
--------------------------------------
| 1 | 2 | 2 (expected 2-0=2)
| 2 | 8 | 8 (expected 8-2=6)
Could anybody highlight why the #c variable is not updating from grouped row to grouped row as expected?
SELECT data.a
, data.b
, #c := data.b - #c
FROM (
SELECT a
, max(b) AS b
FROM test
GROUP BY a
) AS data
ORDER BY a
Example
The 'documented' solution might look like this...
SELECT x.*
, #c := b - #c c
FROM test x
JOIN
( SELECT a,MAX(b) max_b FROM test GROUP BY a ) y
ON y.a = x.a
AND y.max_b = x.b
JOIN (SELECT #c:= 0) vals;
Firstly, I apologize for the terrible wording, but I'm not sure how to describe what I'm doing...
I have a table of computer types (id, type, name), called com_types
id | type | name
1 | 1 | Dell
2 | 4 | HP
In a second table, I have each individual computer, with a column 'type_id' to denote what type of computer it is, called com_assets
id | type_id | is_assigned
1 | 4 | 0
2 | 1 | 1
I'd like to create a view that shows each computer type, and how many we have on hand and in use, and a total, so the outcome would be
id | type | name | on_hand | in_use | total |
1 | 1 | Dell | 0 | 1 | 1 |
2 | 4 | HP | 1 | 0 | 1 |
As you can see, the on_hand, in_use, and total columns are dependent on the type_id and is_assigned column in the second table.
So far I have tried this...
CREATE VIEW test AS
SELECT id, type, name,
( SELECT COUNT(*) FROM com_assets WHERE type_id = id AND is_assigned = '0' ) as on_hand,
( SELECT COUNT(*) FROM com_assets WHERE type_id = id AND is_assigned = '1' ) as in_use,
SUM( on_hand + in_use ) AS total
FROM com_types
But all this returns is one column with all correct values, except the total equals ALL of the computers in the other table. Will I need a trigger to do this instead?
on_hand is the count of assigned = 0, and in_use is the count of assigned = 1. You can count them together, without the correlated subqueries, like this:
SELECT
com_types.id,
com_types.type,
com_types.name,
COUNT(CASE WHEN com_assets.is_assigned = 0 THEN 1 END) AS on_hand,
COUNT(CASE WHEN com_assets.is_assigned = 1 THEN 1 END) AS in_use,
COUNT(*) AS total
FROM com_types
JOIN com_assets ON com_types.id = com_assets.id
GROUP BY
com_types.id,
com_types.type,
com_types.name