sqlite, counting foreign key references - sql

I have two tables, one that defines lists and another that defines items in the lists. When i run this i only get lists that have items referencing them. i really need to get a result for all rows in the lists table and a count of how many rows in the items table reference each list.
SELECT name, COUNT(items.listId) as itemCount
FROM lists
INNER JOIN items
ON lists._id = items.listId
GROUP BY items.listId
any help would be much appreciated.

Try changing your INNER JOIN to a LEFT OUTER JOIN, and change your GROUP BY to lists._id. I didn't test this!

Related

How to do a query with multiple foreign keys pointing to one table?

I have a PostgreSQL database with two tables (person, item). The person table consists of id, name, and let‘s say 5 item columns with foreign keys referencing to the item table. The item table consists of id, name and description.
I want to do a query now that list the person.id, person.name and the 5 item.name. How can I achieve this? I know something with JOIN but I don‘t get it right now.
You have a problem with your data model. You should not be storing lists of items in separate columns. There are multiple alternatives. The typical solution is a separate table with one row per person and item. You can also store the items as arrays or JSON.
But to answer your question, you need multiple joins:
select p.*, i1.name as item_name_1, i2.name as item_name_2
from person p left join
items i1
on p.item_id_1 = i1.id left join
items i2
on p.item_id_2 = i1.id left join
. . . -- and so on

SQL INNER JOIN without linked column

I have an UltraGrid displaying customer information in it. The way the database is set up, there are 2 tables. Customers and Customer_Addresses. I need to be able to display all of the columns from Customers as well as Town and Region from Customer_Addresses, but I'm under the impression that I'd need Town and Region columns in the Customer table to be able to do this? I've never used an INNER JOIN before so I'm not sure if this is true or not, so can anybody give me pointers on how to do this, or if I need the matching columns or not?
Does it even require an INNER JOIN, or is there an alternative way to do this?
Below are the design views of both of the tables - Is it possible to display Add4 and Add5 from Customer_Addresses with all of Customers?
As long as you have another key column you can use to link the tables (ex. ID_Column), it is better that you use LEFT JOIN.
Example:
SELECT c.col1, ... , c.colN, a.town, a.region FROM Customers c
LEFT JOIN Customer_Addresses a ON a.ID_Column = c.ID_Column
In order to clarify how JOIN types work, look at this picture:
In our case, using a LEFT JOIN will take all information from the Customers table, along with any found matching (on ID) information from Customer_Addresses table.
First of all you need some column in common in two tables, all what you have to do is:
CREATE TABLE all_things
AS
SELECT * (or columns that you want to have in the new table)
FROM Costumers AS a1
INNER JOIN Customer_Addresses AS a2 ON a1.column_in_common = a2.column_in_common
The point is what kind of join do you want.
If you can continue the process without having information in table Costumers or in table Customer_Addresses maybe you need OUTER JOIN or other kind of JOIN.

SQL query with loop

I am having trouble with writing a SQL query in Access with foreign keys. There are two tables, 'Customers'(ID, Name, Surname) and 'Orders'(ID, Customer, Date, Volume). ID fields are primary, and Orders.Customer is a foreign key linked to Customers.ID, so a customer can have many orders or none.
My goal is to do a search on customers based on many criteria, one of which being if customers have at least an order which volume is superior to a certain quantity. I tried joins with SELECT DISTINCT but it still gives me duplicate results, plus I had to create an empty order for every customer without orders if the query didn't use the above condition.
Does anyone have an idea about that? Maybe some special instruction on foreign keys or 2 separate queries?
Based on the information you give, i only can give you hints on what I think you're doing/understanding wrong :
SELECT DISTINCT does select you a unique record, not a unique value, so if your statement selects all fields (*), distinct won't help you much there.
My guess is you had to create an empty order for each customer because you used INNER JOIN, try LEFT OUTER JOIN instead
For example :
SELECT DISTINCT Customers.*
FROM Customers
LEFT OUTER JOIN Orders
ON (Orders.Customer = Customers.id)
WHERE Volume > put_your_value

Multiple Many-to-many bi-directional self-inner-joins without repeating whole query

I have a data model such that items can have many-to-many relationships with other items in the same table using a second table to define relationships. Let's call the primary table items, keyed by item_id and the relationships table item_assoc with columns item_id and other_item_id and assoc_type. Generally, you might use a union to pick up on relationships that may be defined in either direction in the item_assoc table, but you would wind up repeating other parts of the same query just to be sure to pick up associations defined in either direction.
Let's say that you're trying to put together a fairly complex query similar to the following where you want to find a list of items that have related items that COULD have associated cancellation items, but select those that do not have cancellation items:
select
orig.*
from items as orig
join item_assoc as orig2related
on orig.item_id = orig2related.item_id
join items as related
on orig2related.other_item_id = related.item_id
and orig2related.assoc_type = 'Related'
left join item_assoc as related2cancel
on related.item_id = related2cancel.item_id
left join items as cancel
on related2cancel.other_item_id = cancel.item_id
and related2cancel.assoc_type = 'Cancellation'
where cancel.item_id is null
This query obviously only picks up items whose relationships are defined in one direction. For a less complex query, I might solve this by adding a union at the bottom for every permutation of the reverse relationships, but I think that would make the query unnecessarily long and hard to understand.
Is there a way I can define both directions of each relationship without repeating the other parts of the query?
A UNION within item_assoc could help. Assuming you have a DB without a WITH clause you would have to define a view
CREATE VIEW bidirec_item_assoc AS
(
SELECT item_id, other_item_id, assoc_type, 1 as direction FROM item_assoc
UNION
SELECT other_item_id, item_id, assoc_type, 2 as direction FROM item_assoc
)
You can now use bidirec_item_assoc in your queries where you have used items_assoc before.
Edited Out: You could add columns for direction and relationtype, of course
Simplify, simplify, simplify: Don't involve tables in the query that aren't needed.
The following query should be equivalent to your sample query and more expressive of your intent:
select i.*
from items i
where not exists ( select *
from item_assoc r
join item_assoc c on c.item_id = r.item_id
and c.assoc_type = 'Cancellation'
where r.item_id = i.item_id
and r.assoc_type = 'Related'
)
It should select the set of items that aren't related to an item that has been cancelled. There's not need to join against the items table 3 times.
Further, your original query will have duplicate rows: every row in the first item table (orig) will be duplicated once for every related item.

Inner join sql statement

I have two tables, Invoices and members, connected by PK/FK relationship through the field InvoiceNum. I have created the following sql and it works fine, and pulls 44 records as expected.
SELECT
INVOICES.InvoiceNum,
INVOICES.GroupNum,
INVOICES.DivisionNum,
INVOICES.DateBillFrom,
INVOICES.DateBillTo
FROM INVOICES
INNER JOIN MEMBERS ON INVOICES.InvoiceNum = MEMBERS.InvoiceNum
WHERE MEMBERS.MemberNum = '20032526000'
Now, I want to replace INVOICES.GroupNum and INVOICES.DivisionNum in the above query with GroupName and DivisionName. These values are present in the Groups and Divisions tables which also have the corresponding Group_num and Division_num fields. I have created the following sql. The problem is that it now pulls 528 records instead of 44!
SELECT
INVOICES.InvoiceNum,
INVOICES.DateBillFrom,
INVOICES.DateBillTo,
DIVISIONS.DIVISION_NAME,
GROUPS.GROUP_NAME
FROM INVOICES
INNER JOIN MEMBERS ON INVOICES.InvoiceNum = MEMBERS.InvoiceNum
INNER JOIN GROUPS ON INVOICES.GroupNum = GROUPS.Group_Num
INNER JOIN DIVISIONS ON INVOICES.DivisionNum = DIVISIONS.Division_Num
WHERE MEMBERS.MemberNum = '20032526000'
Any help is greatly appreciated.
You have at least one relation between your tables which is missing in your query. It gives you extra records. Find all common fields. Say, are divisions related to groups?
The statement is fine, as far as the SQL syntax goes.
But the question you have to ask yourself (and answer it):
How many rows in Groups do you get for that given GroupNum?
Ditto for Divisions - how many rows exist for that DivisionNum?
It would appear that those numbers aren't unique - multiple rows exist for each number - therefore you get multiple rows returned