Find first subset where sum of row group equals given value - sql

I have table in PostgreSQL:
CREATE TABLE test (
id VARCHAR PRIMARY KEY,
name VARCHAR NOT NULL,
amount INTEGER NOT NULL
);
I want SQL to give first combination of tests rows where names are equals and sum of amount test group with same name are equal to a given value
In other words.
If i have values
INSERT INTO test VAlUES
('a', 'name1', 1),
('b', 'name1', 2),
('c', 'name1', 3),
('d', 'name2', 1),
('e', 'name2', 2),
('f', 'name2', 5);
and want find all ids of tests where sum equal 3 the output should be
a,
b,
d,
e
or
c,
d,
e

Related

How to concat all values associated with a key?

I have the following schema:
CREATE TABLE table1
(
user,
phoneType, --from ['A','B','C','D', 'E'], user can have any number of any type
uniquePhoneID, --unique string identifying the phone
day_id --date; record does not necessarily exist for every seen user + phoneType every day, represented as number in example
);
INSERT INTO table1
VALUES (1, 'A', xyz, 1),
(1, 'A', abc, 1),
(1, 'B', def, 2),
(1, 'A', xyz, 2),
(1, 'C', hij, 4),
(1, 'A' xyz, 5),
(2, 'C', w, 9),
(2, 'D', z, 10),
(2, 'A', p, 10),
(2, 'E', c, 11),
(3, 'A', r, 19),
(3, 'B', q, 19),
(3, 'B', q, 20),
(3, 'B', f, 20),
(3, 'B', y, 21);
A single user, uniquePhoneID, day_id will only show up at most once, but not necessarily at all on any given day.
I am looking to concatenate each user in the table with their 4 phoneTypes in alphabetical order, so the result is as follows:
1 | AABC
2 | ACDE
3 | ABBB
I have tried a few different ways of doing this but I am unsure how to get the answer I am looking for.
I think user is a reserved word, so you will have to resolve that. Otherwise, I think something like this will work for you:
select user, string_agg (phonetype, '' order by phonetype)
from table1
group by user
-- EDIT 4/21/2022 --
Aah, okay. I did not glean that from the original question.
What if you used the distinct on the original table before the aggregation?
select userid, string_agg (phonetype, '' order by phonetype)
from (select distinct userid, phonetype, uniquephoneid from table1) x
group by userid
I got these results from this version:
1 AABC
2 ACDE
3 ABBB
If that logic still doesn't work, can you alter the sample data to find an example where it fails?

How to select all records from one table that do not exist in another table for certain condition in another table?

All Books Table
CREATE TABLE [dbo].[Book](
[Id] [uniqueidentifier] NOT NULL,
[ISBN10] [nvarchar](50) NULL)
Books which a seller has
CREATE TABLE [dbo].[BookSeller](
[Id] [uniqueidentifier] NOT NULL,
[ISBN10] [nvarchar](50) NULL,
[SellerId] int NOT NULL
)
Inserting records in Database Book
INSERT INTO BOOK (Id, ISBN10)
VALUES
(NEWID(), 'A'),
(NEWID(), 'B'),
(NEWID(), 'C'),
(NEWID(), 'D'),
(NEWID(), 'E'),
(NEWID(), 'F'),
(NEWID(), 'G')
Inserting records in Database BookSeller
INSERT INTO [BookSeller] (Id, ISBN10, SellerId)
VALUES
(NEWID(), 'A', 1),
(NEWID(), 'B', 1),
(NEWID(), 'B', 2),
(NEWID(), 'C', 1),
(NEWID(), 'C', 3),
(NEWID(), 'C', 4),
(NEWID(), 'D', 3),
(NEWID(), 'E', 3),
(NEWID(), 'F', 1),
(NEWID(), 'G', 3)
Book
Id ISBN10
280C283E-4087-4AFF-9761-358E8F7BC302 A
9FE76BBC-4AB1-436E-8135-2A13FA15CD24 B
C8098DE4-2FC9-4710-B7F9-1D4A92A058CF C
E48D1CCE-1408-45F6-96BA-7439F56640CC D
9EF7EFD6-659F-4109-A78A-5CB3E54CDC3E E
078EB851-945B-4728-9D0F-F45B8A7D742D F
C33943D5-D01C-480D-BFA5-1B48AA59EDE7 G
BookSeller
Id ISBN10 SellerId
73CC3266-98CB-426F-AD51-312ADD9CBAF9 A 1
37F09E06-8598-4DB1-9693-F47438B3CB52 B 1
E7A06C9C-8EFC-43F9-A44E-55B5D839B5ED B 2
A336D899-CA32-47CA-8E39-44F816E08FB0 C 1
11AC0177-9E2D-4AA3-858E-F09C47ACE2E5 C 3
E9A32B1B-66E5-4734-AB87-48FA3D95A34A C 4
60C0D7CD-6F27-4CEE-A3C5-344542623D87 D 3
E8B00921-1985-4FD2-8024-6D03D55DB869 E 3
1D8A2AF3-512F-4B7E-8857-2279A36F851D F 1
00E2366E-1478-4408-A265-399E77575714 G 3
I want Books which are not contained by Seller 1 and 3. Other might have. So with current entry no records should be returned but it is returning
Select B.ISBN10 from Book B
LEFT JOIN BookSeller S
ON B.ISBN10 = S.ISBN10
Where SellerId NOT IN (1, 3)
Wrong result
ISBN10
B
C
Ideally no result should have been returned as all books are there for 1 and 3
I want to avoid subquery because subquery with too many records can cause performamnce
You want a not exists i.e. select all from Book where not exists a record in BookSeller for the same book and SellerId 1 or 3.
select B.ISBN10
from Book B
where not exists (
select 1
from BookSeller S
where B.ISBN10 = S.ISBN10
and SellerId IN (1, 3)
)
Note - your question title actually gives you the answer :)
Also with regard to your comment about not using sub-queries; you should not restrict your options by premature optimisation as the query engine is usually much better than you might think. I can assure you I have used such a construct on large tables with no issues.
You should always build your queries using the most straightforward logic you can and trust SQL Server to build a good query plan. By trying to optimise yourself you may in fact force a more complex query plan. Of course if you actually do run into performance issues, then its time to dig in an investigate. But you do that scientifically i.e. by measuring the performance of different options using the execution plan.

Find the Biggest Number of Consecutive Occurrence of values in Table

I have the following table
create table Launches (Id int, Name char)
insert into Launches values
(1, 'A'),
(2, 'A'),
(3, 'B'),
(4, 'B'),
(5, 'B'),
(6, 'B'),
(7, 'C'),
(8, 'B'),
(9, 'B')
The result should be
4 - B
From 3 to 6
Similar question -
Count Number of Consecutive Occurrence of values in Table
You can subtract an enumerated value for each name to get a constant for adjacent values that are the same. The rest is aggregation:
select top (1) name, count(*), min(id), max(id)
from (select l.*,
row_number() over (partition by name order by id) as seqnum
from #Launches l
) l
group by (id - seqnum), name
order by count(*) desc;
Here is a db<>fiddle.

Select Id where column takes all values in

Please help me with an SQL query. Here go test tables with data:
CREATE TABLE "Cats"
(
"CatId" SERIAL PRIMARY KEY,
"Name" character varying NOT NULL
);
CREATE TABLE "Measures"
(
"MeasureId" SERIAL PRIMARY KEY,
"CatId" integer NOT NULL REFERENCES "Cats",
"Weight" double precision NOT NULL,
"MeasureDay" integer NOT NULL
);
INSERT INTO "Cats" ("Name") VALUES
('A'), ('B'), ('C')
;
INSERT INTO "Measures" ("CatId", "Weight", "MeasureDay") VALUES
(1, 5.0, 1),
(1, 5.3, 2),
(1, 6.1, 5),
(2, 3.2, 1),
(2, 3.5, 2),
(2, 3.8, 3),
(2, 4.0, 4),
(2, 4.0, 5),
(3, 6.6, 1),
(3, 6.9, 2),
(3, 7.0, 3),
(3, 6.9, 4)
;
How do I select those CatId that have measures for ALL 5 days (MeasureDay takes all values in (1, 2, 3, 4, 5)) ?
On this test data, the query should return 2 since only Cat with CatId = 2 has measures for all days (1, 2, 3, 4, 5).
I assume that I should use GROUP BY "CatId" and HAVING clauses, but what kind of query should be inside HAVING?
try like this using group by
select CatId
from Measures
where MeasureDay in (1, 2, 3, 4, 5)
group by CatId
having count(distinct MeasureDay) = 5;
You can use aggregation and a having clause:
select m.CatId
from measures m
group by m.CatId
having count(distinct measureDay) = 5;

Retrieving consecutive rows (and the counts) with the same values

I've got a table with almost 10 million views and would to run this query on the latest million or hundred thousand or so.
Here's a SQL fiddle with example data and input/output: http://sqlfiddle.com/#!9/340a41
Is this even possible?
CREATE TABLE object (`id` int, `name` varchar(7), `value` int);
INSERT INTO object (`id`, `name`, `value`)
VALUES
(1, 'a', 1),
(2, 'b', 2),
(3, 'c', 100),
(4, 'a', 1),
(5, 'b', 2),
(6, 'c', 200),
(7, 'a', 2),
(8, 'b', 2),
(9, 'c', 300),
(10, 'a', 2),
(11, 'b', 2),
(12, 'a', 2),
(13, 'b', 2),
(14, 'c', 400)
;
-- Want:
-- name, max(id), count(id)
-- 'a', 4, 2
-- 'b', 14, 5
-- 'a', 12, 3
If you want the latest and the id is implemented sequentially, then you can do this using limit or top. In SQL Server:
select top 100000 o.*
from object o
order by id desc;
In MySQL, you would use limit:
select o.*
from object o
order by id desc
limit 100000
select name, count(id) cnt, max(id) max_id, max(value) max_v
from
(select
top 1000000 -- MS SQL Server
id,name,value
from myTable
limit 1000000 --mySQL
order by id desc)
group by name
remove line which doesn't match your server.