I have this table
serie number
----- ------
A 1
A 2
A 3
A 5
B 1
B 3
I want to show a result like this
serie ocurrences last_number_value
----- ---------- -----------------
A 4 5
B 2 3
I managed to get the ocurrences number with
SELECT serie, number, COUNT(*) AS ocurrences FROM table_name GROUP BY serie
But, how to show the last number too?
This will get you the result your looking for:
CREATE TABLE test (
serie varchar(1) NOT NULL,
num int(1) NOT NULL
);
INSERT INTO test (serie, num) VALUES
('A', 1),
('A', 2),
('A', 3),
('A', 5),
('B', 1),
('B', 3);
If the row order matters:
SELECT
a.serie,
(SELECT count(*) FROM test WHERE serie=a.serie) as occurances,
a.num
FROM
test AS a
LEFT JOIN test AS b on a.serie=b.serie AND a.num<b.num
WHERE
b.serie IS NULL;
If the order or the rows do NOT matter:
SELECT
a.serie,
COUNT(*) AS occurances,
MAX(a.num) AS last_number_value
FROM
test AS a
GROUP BY a.serie;
Related
These three tables are part of a larger order management system:
orders
o_id c_id
1 1
2 1
3 2
4 3
5 3
6 4
7 5
order_items
o_id p_id
1 1
2 2
3 1
3 2
3 8
4 1
4 2
5 8
5 9
6 4
6 5
7 12
customers
c_id name
1 Doug
2 Tammy
3 Bill
4 Don
5 Kate
I want to find ALL pairs of customers where the second customer in the pair has purchased NONE of the products that the first customer in the pair has purchased. I can't seem to figure this out! My best attempt was grabbing the count of all unique products and trying to see if I could group and reduce by leveraging that count.
Expected Output
c_id1 c_id2
4 1
4 2
4 3
4 5
5 1
5 2
5 3
Or the exact opposite (no duplicates).
CREATE TABLE orders (
o_id INT,
c_id INT
);
INSERT INTO orders (o_id, c_id) VALUES
(1, 1),
(2, 1),
(3, 2),
(4, 3),
(5, 3),
(6, 4),
(7, 5);
CREATE TABLE order_items (
o_id INT,
p_id INT
);
INSERT INTO order_items (o_id, p_id) VALUES
(1, 1),
(2, 2),
(3, 1),
(3, 2),
(3, 8),
(4, 1),
(4, 2),
(5, 8),
(5, 9),
(6, 4),
(6, 5),
(7, 12);
CREATE TABLE customers (
c_id INT,
name VARCHAR(10)
);
INSERT INTO customers (c_id, name) VALUES
(1, 'Doug'),
(2, 'Tammy'),
(3, 'Bill'),
(4, 'Don'),
(5, 'Kate');
Test
WITH cte AS ( SELECT *
FROM orders
NATURAL JOIN order_items
NATURAL JOIN customers )
SELECT t1.c_id id1, t2.c_id id2
FROM customers t1
JOIN customers t2 ON t1.c_id < t2.c_id
WHERE NOT EXISTS ( SELECT NULL
FROM cte cte1, cte cte2
WHERE cte1.c_id = t1.c_id
AND cte2.c_id = t2.c_id
AND cte1.p_id = cte2.p_id );
fiddle
The idea is to generate all pairs of customers (using a cross join).
Then check that they do not have the same items. This is a little tricky, but it involves not exists and joining down to the item level to see if any match on orders that match the customers:
select c1.c_id, c2.c_id
from customers c1 cross join
customers c2
where not exists (select 1
from order_items oi1 join
order_items oi2
on oi1.i_id = oi2.i_id join
orders o1
on o1.o_id = oi1.o_id join
orders o2
on o2.o_id = oi2.o_id
where o1.c_id = c1.c_id and
o2.c_id = o2.c_id
);
I am not great at SQL queries so I thought I'd ask here. I have a table my_table:
NOTE : Consider all the columns as strings. I just represent them as numbers here for a better understanding.
A B C
-----
1 2 3
2 2 3
2 5 6
3 5 6
I want the result to be-
A B C
-----
1 2 3
2 5 6
So basically, dropping duplicate pairs for B, C, and taking the first occurrence of A for that pair of B, C.
Seems you need to consider the minimum of the column A and grouping by B and C :
select min(cast(A as unsigned)) as A, cast(B as unsigned) as B, cast(C as unsigned) as C
from my_table
group by B , C
cast(<column> as unsigned) conversion is used to make them numeric.
Demo
You seem to want aggregation:
select min(a) as a, b, c
from t
group by b, c;
I assumes "first" means the minimum value of a. SQL tables represent unordered sets, so that seems like the most sensible interpretation.
first, you'd better post some of the something you tried here.
In mysql 8.0 you can use row_number() over (partition by B, C order by A) to slove this question.
CREATE TABLE Table1
(`A` int, `B` int, `C` int)
;
INSERT INTO Table1
(`A`, `B`, `C`)
VALUES
(1, 2, 3),
(2, 2, 3),
(2, 5, 6),
(3, 5, 6)
;
select `A`, `B`, `C` from (
select *,row_number() over (partition by `B`, `C` order by `A`) rnk from Table1
) T
where rnk = 1;
A | B | C
-: | -: | -:
1 | 2 | 3
2 | 5 | 6
db<>fiddle here
if mysql < 8.0 you can follow this answer ROW_NUMBER() in MySQL
Update :
if like #forpas says : taking the first occurrence of A for that pair of B, C is not solved by order by A.
You have to sort the rownum first :
CREATE TABLE Table1
(`A` int, `B` int, `C` int)
;
INSERT INTO Table1
(`A`, `B`, `C`)
VALUES
(2, 2, 3),
(1, 2, 3),
(2, 5, 6),
(3, 5, 6)
;
SET #rownum:=0;
select `A`, `B`, `C` from (
select *,row_number() over (partition by `B`, `C` order by rownum) rnk from (
select *,#rownum:=#rownum+1 AS rownum from Table1
) T
) T
where rnk = 1;
✓
A | B | C
-: | -: | -:
2 | 2 | 3
2 | 5 | 6
db<>fiddle here
select min(A) as A,B,C
from Table1
group by B,C
As, you requested this will get the minimum value of A for combinations of B and C.
The example below builds a table that extracts the first two score values by userId and passageId. How can I select only records where each record in the new table contains at least two scores (i.e. ignore records where score2 is null)?
Example
Code:
drop table if exists simon;
drop table if exists simon2;
Create table simon (userId int, passageId int, score int);
Create table simon2 (userId int, passageId int, score1 int,score2 int);
INSERT INTO simon (userId , passageId , score )
VALUES
(10, 1, 2),
(10, 1, 3),
(10, 2, 1),
(10, 2, 1),
(10, 2, 5),
(11, 1, 1),
(11, 2, 2),
(11, 2, 3),
(11, 3, 4);
insert into simon2(userId,passageId,score1,score2)
select t.userId, t.passageId,
substring_index(t.scores,',',1) as score1,
(case when length(t.scores) > 1 then substring_index(t.scores,',',-1)
else null
end
) as score2
from
(select userId,passageId,
substring_index (group_concat(score separator ','),',',2) as scores
from simon
group by userId,passageId) t;
select *from simon2;
This is what I get now:
userId passageId score1 score2
1 10 1 2 3
2 10 2 1 1
3 11 1 1 NULL
4 11 2 2 3
5 11 3 4 NULL
This is what I want:
userId passageId score1 score2
1 10 1 2 3
2 10 2 1 1
4 11 2 2 3
Just add this around your query
Select * from ( ...... ) x where score2 is not null
You have no ordering specifying what score goes into score_1 and score_2, so I'll just use min() and max(). You can then do the logic as:
select s.userid, s.passageid,
max(score) as score_1, max(score) as score_2
from simon s
group by s.userid, s.passageid
having count(*) >= 2;
This doesn't give you exactly the same results for 10/2. However, your results are arbitrary because the group_concat() has no order by. SQL tables represent unordered sets. There is no ordering unless you specify it.
If you want an ordering, then define the table as:
Create table simon (
simonId int auto_increment primary key,
userId int,
passageId int,
score int
);
And then use the simonId column appropriately.
I have two tables like this:
SupplyList (IDSupply is the primary key)
IDSupply PartName Qty
--------- --------- ----
1 C 10
2 B 4
SupplyIndex (IDSupply and Index are the compound primary key)
IDSupply PartName Index
--------- --------- ------
1 C 2
1 C 3
1 C 7
1 C 9
1 C 10
These tables are related to each other with IDSupply.
I want to insert missed records to SupplyIndex table by a query in SQL. In other words, my expected result is SupplyIndex table like below (Index must include numbers from 1 to Qty from SupplyList table)
IDSupply PartName Index
--------- --------- ------ (result)
1 C 1
1 C 2
1 C 3
1 C 4
1 C 5
1 C 6
1 C 7
1 C 8
1 C 9
1 C 10
2 B 1
2 B 2
2 B 3
2 B 4
I did this job in my VB.Net application before and now I want to do it in SQL Server directly.
Would you please help me?
Thanks
Test Data:
create table #supplylist
(
idsupply int,
partname char(20),
qty int
)
insert into #supplylist
select 1,'a',10
union all
select 2,'c',4
create table #idsupply
(
idsupply int,
partname char(20),
indexx int
)
insert into #idsupply
select 1,'a',10
union all
select 2,'c',3
I used Numbers table to accomplish this
with cte
as
(
select
idsupply,
partname,n
from
#supplylist t
cross apply
(
select n from numbers where n <=qty
)b
--final part to check and isnert in other table..same query as above with insert and exists
with cte
as
(
select
idsupply,
partname,n
from
#supplylist t
cross apply
(
select n from numbers where n <=qty
)b
)
insert into #idsupply
select * from cte t1 where not exists (select 1 from #idsupply t2 where t2.indexx=t1.n)
Create Table #SupplyList(IDSupply int Primary Key, PartName char(10),Qty int);
Insert #SupplyList(IDSupply, PartName, Qty) Values
(1, 'C', 10),
(2, 'B', 4);
Create Table #SupplyIndex(IDSupply int, PartName char(10), [Index] int Primary Key (IdSupply, [Index]));
Insert #SupplyIndex(IDSupply, PartName, [Index]) Values
(1, 'C', 2),
(1, 'C', 3),
(1, 'C', 7),
(1, 'C', 9),
(1, 'C', 10);
;With cteMax As
(Select Max([Index]) As MaxIndex From #SupplyIndex),
cteNumbers As
(Select 1 As Number
Union All
Select Number + 1
From cteNumbers n
Cross Join cteMax m
Where n.Number < m.MaxIndex)
Merge #SupplyIndex t
Using (Select sl.IDSupply, sl.PartName, n.Number As Qty From #SupplyList sl Inner Join cteNumbers n On n.Number <= sl.Qty) s
On s.IDSupply = t.IDSupply And s.PartName = t.PartName And s.Qty = t.[Index]
When Not Matched Then Insert(IDSupply, PartName, [Index]) Values(s.IDSupply, s.PartName, s.Qty);
Select * From #SupplyIndex;
go
Drop Table #SupplyList;
go
Drop Table #SupplyIndex
In the query below I have a basic table with two fields course_name and course_id. I am trying to display through the query the top three courses by the amount of times they appear in the table. I am using COUNT, then I am comparing the values in additional select to determine the top three and finally display the results by GROUP by course_id. I am getting a mysql syntax problem. How can I display the top three courses with the amount of times they appear in the table? FIDDLE
SELECT course_name, course_id, COUNT(1) AS cnt
FROM courses
JOIN (SELECT distinct cnt cnt3
FROM courses
ORDER BY cnt DESC
LIMIT 2, 1) x
ON cnt >= cnt3
ORDER by cnt DESC
GROUP BY course_id
Table Schema:
CREATE TABLE courses
(`course_name` varchar(15), `course_id` int)
;
INSERT INTO courses
(`course_name`, `course_id`)
VALUES
('Math', 1),
('Science', 2),
('PHYS', 3),
('Study Hall', 4),
('History', 5),
('Social Studies', 6),
('Math', 1),
('PHYS', 3),
('Math', 1),
('Science', 2),
('Science', 2),
('Study Hall', 4),
('History', 5)
;
Desired Result:
+-------------+-------+
| Course_name | Count |
+-------------+-------+
| Math | 3 |
| Science | 3 |
| PHYS | 2 |
| Study | 2 |
| History | 2 |
+-------------+-------+
Your syntax error is due to this:
ON cnt >= cnt3
cnt is an alias and you can't use it in a join. Also, your order by and group by clauses are in the wrong order.
Edit starts here
Looking at your query, you may have overengineered it. Would this not give you your answer?
select course_name, course_id, count(*) records
from courses
group by course_name, course_id
having count(*) > 1
order by records desc
limit 3
Select course_name,cnt from(
Select course_id,course_name,count(course_id) as cnt group by course_id,course_name
)tmp
Order by cnt desc limit 0,3