SQL Join with Group By - sql

Ok, so i'm trying to write a complex query (at least complex to me) and need some pro help. This is my database setup:
Table: MakeList
| MakeListId | Make |
| 1 | Acura |
| 2 | Chevy |
| 3 | Pontiac |
| 4 | Scion |
| 5 | Toyota |
Table: CustomerMake
| CustomerMakeId | CustomerId | _Descriptor |
| 1 | 123 | Acura |
| 2 | 124 | Chevy |
| 3 | 125 | Pontiac |
| 4 | 126 | Scion |
| 5 | 127 | Toyota |
| 6 | 128 | Acura |
| 7 | 129 | Chevy |
| 8 | 130 | Pontiac |
| 9 | 131 | Scion |
| 10 | 132 | Toyota |
Table: Customer
| CustomerId | StatusId |
| 123 | 1 |
| 124 | 1 |
| 125 | 1 |
| 126 | 2 |
| 127 | 1 |
| 128 | 1 |
| 129 | 2 |
| 130 | 1 |
| 131 | 1 |
| 132 | 1 |
What i am trying to end up with is this...
Desired Result Set:
| Make | CustomerId|
| Acura | 123 |
| Chevy | 124 |
| Pontiac | 125 |
| Scion | 131 |
| Toyota | 127 |
I am wanting a list of unique Makes with one active (StatusId = 1) CustomerId to go with it. I'm assuming i'll have to do some GROUP BYs and JOINS but i haven't been able to figure it out. Any help would be greatly appreciated. Let me know if i haven't given enough info for my question. Thanks!
UPDATE: The script doesn't have to be performant - it will be used one time for testing purposes.

Something like this:
select cm._Descriptor,
min(cu.customerid)
from CustomerMake cm
join Customer cu on cuo.CustomerId = cm.CustomerId and cu.StatusId = 1
group by cm._Descriptor
I left out the MakeList table as it seems unnecessary because you are storing the full make name as _Descriptorin the CustomerMake table anyway (so the question is what is the MakeList table for? Why don't you store a FK to it in the CustomerMake table?)

You want to
(a) join the customer and customermake tables
(b) filter on customer.statusid
(c) group by customermake._descriptor
Depending on your RDBMS, you may need to explicitly apply a group function to customer.customerid to include it in the select list. Since you don't care which particular customerid is displayed, you could use MIN or MAX to just pick an essentially arbitrary value.

Related

DB2 SQL - Limit the number of groups returned

I am trying to find a way to limit the first n groups returned. I have a scenario where I want to only select 10 groups of user data and no more. How would I limit 10 groups of user data where the group size for the user can vary. Some groups may have more than 4 records for a user, some may have less than 4 records for a user. But I only want to get 10 users at a time. I tried thinking about how ROW_NUMBER() and PARTITION BY could be leveraged or even FETCH FIRST N ROWS ONLY could be leveraged, but couldn't come up with a solution.
Below is some sample data. NOTE: The GROUP_NUMBER column doesn't exist in the data set I am working with. It is what I was thinking about creating via SQL so that I can leverage this to select where the "GROUP_NUMBER" < 11 for example. I am absolutely open to other solutions given my question, but this was one solution I was thinking about but didn't know how to do it.
+-----------+--------------+-----------+-----------+----------+------------------+--------------+
| REQUESTID | USERID | COMPANYID | FIRSTNAME | LASTNAME | EMAIL | GROUP_NUMBER |
+-----------+--------------+-----------+-----------+----------+------------------+--------------+
| 157 | test.bulkup1 | 44 | BulkUp | Test | bulkup1#test.com | 1 |
| 157 | test.bulkup1 | 44 | BulkUp | Test | bulkup1#test.com | 1 |
| 157 | test.bulkup1 | 44 | BulkUp | Test | bulkup1#test.com | 1 |
| 162 | test.bulkup2 | 44 | BulkUp | Test | bulkup2#test.com | 2 |
| 162 | test.bulkup2 | 44 | BulkUp | Test | bulkup2#test.com | 2 |
| 162 | test.bulkup2 | 44 | BulkUp | Test | bulkup2#test.com | 2 |
| 162 | test.bulkup2 | 44 | BulkUp | Test | bulkup2#test.com | 2 |
| 187 | test.bulkup3 | 44 | BulkUp | Test | bulkup3#test.com | 3 |
| 187 | test.bulkup3 | 44 | BulkUp | Test | bulkup3#test.com | 3 |
| 187 | test.bulkup3 | 44 | BulkUp | Test | bulkup3#test.com | 3 |
| 187 | test.bulkup3 | 44 | BulkUp | Test | bulkup3#test.com | 3 |
| 192 | test.bulkup4 | 44 | BulkUp | Test | bulkup4#test.com | 4 |
+-----------+--------------+-----------+-----------+----------+------------------+--------------+
You can use dense_rank(). I think you want:
select t.*
from (select t.*,
dense_rank() over (order by requestId) as seqnum
from t
) t
where seqnum <= 3;

SQL Server 2016 count similar rows as a column without duplicating query

I have a SQL query that returns data similar to this pseudo-table:
| Name | Id1 | Id2 | Guid |
|------+-----+-----+------|
| Joe | 1 | 1 | 1123 |
| Joe | 2 | 1 | 1123 |
| Joe | 3 | 1 | 1120 |
| Jeff | 1 | 1 | 1123 |
| Moe | 3 | 42 | 1120 |
I would like to display an additional column on the output, listing the total number of records that have matching GUIDs to a given row, like this:
| Name | Id1 | Id2 | Guid | # Matching |
+------+-----+-----+------+------------+
| Joe | 1 | 1 | 1123 | 3 |
| Joe | 2 | 1 | 1123 | 3 |
| Joe | 3 | 1 | 1120 | 2 |
| Jeff | 1 | 1 | 1123 | 3 |
| Moe | 3 | 42 | 1120 | 2 |
I was able to accomplish this by joining the query with itself, and doing a count. However, the query is rather large and takes awhile to complete, is there any way I can accomplish this without joining the query with itself?
You want a window function:
select t.*, count(*) over (partition by guid) as num_matching
from t;

Outer Join multible tables keeping all rows in common colums

I'm quite new to SQL - hope you can help:
I have several tables that all have 3 columns in common: ObjNo, Date(year-month), Product.
Each table has 1 other column, that represents an economic value (sales, count, netsales, plan ..)
I need to join all tables on the 3 common columns giving. The outcome must have one row for each existing combination of the 3 common columns. Not every combination exists in every table.
If I do full outer joins, I get ObjNo, Date, etc. for each table, but only need them once.
How can I achieve this?
+--------------+-------+--------+---------+-----------+
| tblCount | | | | |
+--------------+-------+--------+---------+-----------+
| | ObjNo | Date | Product | count |
| | 1 | 201601 | Snacks | 22 |
| | 2 | 201602 | Coffee | 23 |
| | 4 | 201605 | Tea | 30 |
| | | | | |
| tblSalesPlan | | | | |
| | ObjNo | Date | Product | salesplan |
| | 1 | 201601 | Beer | 2000 |
| | 2 | 201602 | Sancks | 2000 |
| | 5 | 201605 | Tea | 2000 |
| | | | | |
| | | | | |
| tblSales | | | | |
| | ObjNo | Date | Product | Sales |
| | 1 | 201601 | Beer | 1000 |
| | 2 | 201602 | Coffee | 2000 |
| | 3 | 201603 | Tea | 3000 |
+--------------+-------+--------+---------+-----------+
Thx
Devon
It sounds like you're using SELECT * FROM... which is giving you every field from every table. You probably only want to get the values from one table, so you should be explicit about which fields you want to include in the results.
If you're not sure which table is going to have a record for each case (i.e. there is not guaranteed to be a record in any particular table) you can use the COALESCE function to get the first non-null value in each case.
SELECT COALESCE(tbl1.ObjNo, tbl2.ObjNo, tbl3.ObjNo) AS ObjNo, ....
tbl1.Sales, tbl2.Count, tbl3.Netsales

Summarize tables with percent of sum in single query

I have an ACTIVE_TRANSPORTATION table:
+--------+----------+--------+
| ATN_ID | TYPE | LENGTH |
+--------+----------+--------+
| 1 | SIDEWALK | 20.6 |
| 2 | SIDEWALK | 30.1 |
| 3 | TRAIL | 15.9 |
| 4 | TRAIL | 40.4 |
| 5 | SIDEWALK | 35.2 |
| 6 | TRAIL | 50.5 |
+--------+----------+--------+
It is related to an INSPECTION table via the ATN_ID:
+---------+--------+------------------+
| INSP_ID | ATN_ID | LENGTH_INSPECTED |
+---------+--------+------------------+
| 101 | 2 | 15.2 |
| 102 | 3 | 5.4 |
| 103 | 5 | 15.9 |
| 104 | 6 | 20.1 |
+---------+--------+------------------+
I want to summarize the information like this:
+----------+--------+-------------------+
| TYPE | LENGTH | PERCENT_INSPECTED |
+----------+--------+-------------------+
| SIDEWALK | 85.9 | 36% |
| TRAIL | 106.8 | 23% |
+----------+--------+-------------------+
How can I do this within a single query?
Here is the updated answer using ACCESS 2010. Note that LENGTH is reserved in ACCESS, so it needs to be changed to LENGTH_
SELECT
TYPE,
SUM(LENGTH) as LENGTH_,
SUM(IIF(ISNULL(LENGTH_INSPECTED),0, LENGTH_INSPECTED))/SUM(LENGTH) as PERCENT_INSPECTED
FROM
ACTIVE_TRANSPORTATION A
LEFT JOIN INSPECTION B
ON A.ATN_ID = B.ATN_ID
GROUP BY TYPE
Here is the answer using T-SQL in SQL SERVER 2014 I had originally
SELECT SUM(LENGTH) as LENGTH,
SUM(ISNULL(LENGTH_INSPECTED,0))/SUM(LENGTH) as PERCENT_INSPECTED,
TYPE
FROM
ACTIVE_TRANSPORTATION A
LEFT JOIN INSPECTION B
ON A.ATN_ID = B.ATN_ID
GROUP BY TYPE
Let me know if you need it to be converted to percent, rounded, etc, but I'm guessing that part is easy for you.

Joining data from two result rows on a numerical range

I am trying to create a custom interface for a system that tracks tickets.
I have got tickets in a table of the form:
+----------------------+
| Section | Row | Seat |
+----------------------+
| 15 | A | 100 |
| 15 | A | 102 |
| 15 | A | 103 |
| 15 | A | 110 |
| 15 | A | 111 |
| 15 | B | 102 |
| 15 | B | 103 |
| 15 | B | 104 |
| 15 | C | 99 |
| 15 | C | 100 |
| 15 | C | 101 |
| 15 | C | 102 |
| 15 | C | 103 |
| 15 | C | 104 |
+----------------------+
I am trying to display the ticket 'blocks' where seats behind each other are marked as such. i.e. I'd like to be able to display:
+------------------------------------------------+
| Section | Row | Seat Range | Overlaps Previous |
+------------------------------------------------+
| 15 | A | 100 - 103 | No |
| 15 | B | 102 - 104 | Yes |
| 15 | C | 99 - 104 | Yes |
| 15 | A | 110 - 111 | No |
+------------------------------------------------+
Any thoughts?
You could have an additional relation that assignes all neighbouring seats to a given one. This will then also work better than any soly numerical scheme for any sort of separation of your seats. And you could allow for a neighbourhood across rows. From there you could then iteratively define any block of free seats.
If this is about supporting a cashier, I tend to think I would not solely address that in the database but seek for an integration with the GUI to identify the blocks via some backtracking upon a click on a first free seat.