Get row that matches all multiple rows from another table - sql

I have 2 tables:
One table contains customer ids and a service id that the customer subscribes to.
The second table contains the service id's and a service description for all types of services.
What I am trying to do is print out all the customer ids from the first table that have at least 5 matching unique services. Here is what I came up with but its super hacky:
select * from customers left join services where customer.serviceid = services.sid group by servicesid having count(servicesid) >= 5;
is there a better way of doing this?

Assuming that you have a properly formed database, then any value of serviceid should be valid.
If you want matching customers, use group by:
select c.customerid
from customers c
group by c.customerid
having count(servicesid) >= 5;
If there could be duplicates in the customers table, then use count(distinct servicesid) >= 5.

Related

SQL Joining tables - To only display rows that have matching parameters

I have 2 tables that I am attempting to join but to only display rows of data based on specific parameters.
Table one: "orders"
Table two: "cash_tracking"
Matching parameters from both tables: "orders.user_id" and "cash_tracking.user_id" and the user_id is 2640
The result I want to see is all the "orders.name" from the "user_id=2640" on a specific shop "shop_id = 7777" and based on a specific register number from the "cash_tracking" table eg. "cash_transaction_reg=444454"
However, when I run my query it shows me every single order on this shop instead of the ones related to the user 2640 on this specific register - 444454
Here is what I have so far:
SELECT orders.name
FROM orders
Inner JOIN cash_tracking
ON orders.user_id = cash_tracking.user_id
WHERE orders.shop_id = 7777
AND cash_tracking.user_id=2640
AND cash_tracking.cash_transaction_reg=444454
You select all orders for user_id, shoud be some join orders.Id = cash_tracking.OrderId

SQL Joining on 5 Tables - Inclusion & Exclusion

I want to join 5 tables to come up with 3 different result sets.
My tables are:
Customers - contains email address (unique id), email address domain name, account name, demographic info, etc (Customers)
Product 1 customer account names (Product1Accounts)
Product 1 customer email address domain names (Product1Domains)
Product 2 customer account names (Product2Accounts)
Product 2 customer email address domain names (Product2Domains)
The 3 results I need are:
Product 1 customers excluding Product 2 customers
Product 2 customers excluding Product 1 customers
Customers of both Product 1 and 2
Side Note: a customer of each product could be identified by account OR domain name.
I can create the following to come up with matches on table 1,2,3 or 1,4,5 but I am getting hung up on how to incorporate the exclusions
SELECT *
FROM Customers
INNER JOIN Product1Accounts
ON Customers.Company=Product1Accounts.Account
UNION
SELECT *
FROM Customers
INNER JOIN Product1Domains
on Customers.Email_Address_Domain=Product1Domains.Domain
I'm also not sure how to obtain the 3rd result set I am looking for... any help or advice on how to write this code better would be appreciated.
For the third result you can just keep adding UNIONs to get the additional results for the Product2 tables (which really smells like the database needs to be normalized).
For the first two results the EXCEPT keyword should work. I don't work with SQL Express, so I'm not sure if it's available in that version of SQL Server, but check it out. Your code would look like:
(
SELECT C.Company
FROM Customers C
INNER JOIN Product1Accounts PA ON PA.Account = C.Company
UNION
SELECT C.Company
FROM Customers C
INNER JOIN Product1Domains PD ON PD.Domain = C.Email_Address_Domain
)
EXCEPT
(
SELECT C.Company
FROM Customers C
INNER JOIN Product2Accounts PA ON PA.Account = C.Company
UNION
SELECT C.Company
FROM Customers C
INNER JOIN Product2Domains PD ON PD.Domain = C.Email_Address_Domain
)
I think your database structure is not correct, you are having 2 different tables for the 2 products. Does it mean that if in future you have 5 more products, you will have 5 more tables?
I think its better to remove the product1 and product2 tables and create one product table, then you can have another table that can be called productType which have the information about the type of the product and with a Foreign Key its connected to your main product Table
Also does any of your product tables have a Foreign Key available in your customers table? from what I can see they name of the columns you are trying to do the join on are not really clear to be a foreign key.

SQL Query that returns only records with multiple rows

I have a database with two tables: Customers and Services.
The Customer table has account information and the Services table has individual records of every service my company has performed.
The Services table is linked to the Customer table with an ID column where Customers.ID = Services.CustomerID.
I am trying to perform a query which will return the customer name and account number for only those customers where more than one service has been performed within a specified date range. For example, show me all customers where I've performed work more than twice in 2015.
How do I write this type of query so that only those with multiple service visits are returned? I can do this using cursors, counting results, etc. but it seems there must be a more efficient way.
Just use a JOIN and a GROUP BY like so:
SELECT Customers.ID
FROM Customers
JOIN Services ON Customer.ID=Services.CustomerID
--WHERE your Services date check here
GROUP BY Customers.ID -- you can add more columns from the customers table here and in the select as needed
HAVING SUM(1)>1
You can add a WHERE clause to filter the Services' date range (just before the GROUP BY).
Select Id from Customers C where count (select * from Services S where C.id = S.CustomersId ) > 1
SELECT Customers.CustomerID
,Customers.Name
,Customers.AcoountNumber
FROM Customers
JOIN
(
select Services.CustomerID, Services.CustomerID as totalServices
from Services
where Services.date BETWEEN #FROM_DATE AND #TO_DATE
group by Services.CustomerID
having count(Services.CustomerID) >1
) AS CustomersMoreThan1 on Customers.CustomerID=CustomersMoreThan1.CustomerID
This query allows you to add more columns from your Customer table without having to modify your GROUP BY.

Data Mart - how to handle one to many relation?

I have a following situation that I am not sure how to handle:
There is a table Inovice_Item, Service and ServiceLang. Invoice_item table has FK_Service key (one to one). Service table has FK_Service_Lang key. ServiceLang table has FK_Service key so it makes it many to many relation.
In other words, Invoice_Item can have multiple ServiceLang records, which means that when I make a join query, invoice_item records get duplicated. What are the options to handle such situations?
I would like to have ServiceLang dimension in the cube, but I am not sure how to handle duplicates caused by join.
EDIT
I've made an example:
The queries are as following:
-- One lang for service A, two langs for service B
select * from ServiceLang
-- Two records: A and B
select * from Service
-- Total amount is 20
select * from InvoiceItem
-- Query to populate Fact table
-- Total amount is 30
select *
from InvoiceItem II
inner join Service S on II.FK_Service = S.PK_Service
inner join ServiceLang SL on S.PK_Service = SL.FK_Service
So, if there are two Service_Lang records related to one service than there is a duplicate row meaning that total services amount would be 30 but it should be 20. So, my question is how to handle these situations?
From the description you are mistaken. Each Invoice_Item has one and only one Service and each Service has one and only one Service_Lang. However each Service_Lang has many Service records and each Service has many Invoice_Item records
The relationships are
Invoice (n) <- (1) Service (n) <- (1) Service_Item
Thus the JOIN would be
Select Invoice_Item.*, Service_Lang.WhateverColumnYouWant
From Invoice_Item
Inner Join Service On Service.Key = Invoice_Item.FK_Service_Key
Inner Join Service_Lang On Service_Lang.Key = Service.FK_Service_Lang_Key
Edit: So the Service table does not have a FK_Service_Lang key on it, in which case you can only select one of the possible values for languages associated with the service. You could select the Min, the Max or some derivation based upon your preferred language, some examples...
Select InvoiceItem.*,
Case When Exists (Select 1 From ServiceLang
Where ServiceLang.FK_Service = InvoiceItem.FK_Service
And ServiceLang.Name = 'English')
Then 'English'
Else (Select Max(Name) From ServiceLang
Where ServiceLang.FK_Service = InvoiceItem.FK_Service)
End As ServiceLanguage,
(Select Max(Name) From ServiceLang
Where ServiceLang.FK_Service = InvoiceItem.FK_Service) As MaxLanguage,
(Select Min(Name) From ServiceLang
Where ServiceLang.FK_Service = InvoiceItem.FK_Service) As MinLanguage
From InvoiceItem
I've no idea how big your ServiceLang table is but good practice would be ensure there is a key on the FK_Service column

SQL, Select from table A and use result ID to loop though table B?

I have a windows server running MS-SQL 2008.
I have a customer table that I need to select the id's of all customers that are Active, On Hold, or Suspended.
get all customers that are Y= current active customer H=on hold S=Suspended
select id from customer where active = 'Y';
the above statement worked fine for selecting the ID's of the affected customers.
I need to use these results to loop though the following command in order to find out what rates all the affected customers have.
get all rates for a customer
select rgid from custrate where custid = [loop though changing this id with results from first statement];
the id from the customer table coincides with the custid from the custrate table.
So in the end I need a list of all affected customer id's and what rgid's(rate group(s)) they have.
SQL isn't about loops in general and instead you should think in terms of joins.
select customer.id, custrate.rgid, customer.active
from customer
inner join custrate
on customer.id = custrate.custid
where active in ('Y', 'H', 'S")
order by customer.active, customer.id
would be a starting point to think about. However, that is just a wild guess as the schema was not specified nor the relations between the tables.