how to select owned items or items that have been shared in access 2003 - sql

I have two tables, Items and Items_People. Each item has an id and a userid (the person who owns the item). Items_People, the table that shows who the item has been shared with, has an itemid and a userid. I want to get a list of items that the user owns or items that have been shared with that user
Here is what i have so far:
SELECT * FROM Items
WHERE id IN (SELECT itemid as id FROM Items_People where userid = 1)
OR userid=1
This does work, but I'm not sure if a nested select with WHERE IN is the fastest way of doing it. Should I be using some kind of join?

Do some testing to see which runs faster for you. I believe this query will work from what you stated in the question.
SELECT *
FROM Items
OUTER JOIN Items_People on Items.id = Items_People.itemid AND Items_People.userid = 1
WHERE Items.userid=1
Obviously, run this query first to make sure it gives you the same results. Then test each query to see if you notice any difference in speed.

Related

Check if multiple values ALL EXIST in a table

SQL, SQL Server 2016
I've got a table "Characteristics" (from a catalog) and for a product (that comes with a list of characteristics). I need to check, if every item of the list is contained in Characteristics.
Only if all items of the list are present in the table, the catalog is considered valid.
The List of characteristics is simply a table with
ID CHARACTERISTIC
1 Blue
1 Yellow
1 Big
2 Pointy
...
For one item I can do a query like:
SELECT CatalogNumber FROM CHARACTERISTICS
WHERE EXISTS (SELECT * FROM CHARACTERISTICS WHERE Item = ID AND CHARACTERISTIC = 'Characteristic1')
AND EXISTS (SELECT * FROM CHARACTERISTICS WHERE Item = ID AND CHARACTERISTIC = 'Characteristic2')
But since the number of characteristics for each item in the list is different for each item, this approach doesn't work.
Is there a way to check, if all characteristics are in the catalog without resorting to a cursor and a loop?
Thank you in advance
Wolfgang
Select id from Characteristics
group by id
having count(*) = (select count(distinct Characteristic) from Characteristics);
DBfiddle demo

SQL question: how do I find the count of IDs that are always mapped to a 'true' field in another table

I have a database that collects a list of document packages in one table and each individual page in another table
Each page has a PackageID connecting the two tables.
I'm trying to find the count of all packages where ALL pages connected to it have a boolean field (stored on the page table) of true. Even if 1/20 of the pages connected to the packageID is false, I don't want that packageID counted
Right now all I have is:
SELECT COUNT(DISTINCT pages.package_id)
FROM pages
WHERE boolean_field = true
But I'm not sure how to add that if one page w/ that package_id has the boolean_field != true than I don't want it counted. I also want to know the count of those packages that have any that are false.
I'm not sure if I need a subquery, if statement, having clause, or what.
Any direction even if it's what operators I should study on would be super helpful. Thanks :).
select count(*)
from
(
select package_id
from pages
group by package_id
having min(boolean_field) = 1
) tmp
Another way to express this is:
select count(*)
from packages p
where not exists (select 1
from pages pp
where pp.package_id = p.package_id and
not pp.boolean_field
);
The advantage of this approach is that it avoids aggregation, which can be a big win performance wise. It can also take advantage of an index on pages(package_id, boolean_field).

Activerecord query returning doubles while using uniq

I am running the following query with the goal of returning a unique set of customer objects:
Customer.joins(:projects).select('customers.*, projects.finish_date').where("projects.closed = false").uniq
However, this code will generate duplicates if a customer has more than one project active (e.g. closed = true). If I remove the projects.finish_date from the select clause this query works as intended. However, I need this to be in there to be able to sort on that column.
How can I make this query return a unique set of customers?
How can I make this query return a unique set of customers?
This doesn't completely make sense, and probably isn't what you want.
The problem is that you're joining against the projects table, at which point there may be several rows for the same customer with different project finish_dates. These rows are unique and will be returned as multiple unique Customer objects, each with different a finish_date.
If you only want one of these, how is Rails to determine which one? Wouldn't it be a problem if you only had one customer object with one finish_date returned if there are really 10 projects for that customer, each with a different finish_date?
Instead, you probably want something like this:
customers = Customer.joins(:projects).select('customers.*, projects.finish_date').where("projects.closed = false").uniq
customers.group_by(&:id)
This groups all of your same customers together.
OR, you might want:
projects = Project.where(closed: false).includes(:user)
users = projects.map(&:user).uniq
In either case, you're producing a unique set of users from the superset of all user-project joins.
RE Your comments:
If you want to get a list of customers with their most recent associated project, you could use a sub query in your where:
select customers.*, projects.finish_date from customers
inner join projects on projects.customer_id = customers.id
where projects.id = (
select id from projects
where customer.id = project.customer_id
and closed = false
order by finish_date desc
limit 1
)
You can express this using ActiveRecord by embedding the sub-query in a where:
Customer.joins(:projects)
.select('customers.*, projects.finish_date as finish_date')
.where('select id from projects where customer.id = project.customer_id and closed = false order by finish_date desc limit 1')
I have no idea how this will perform for you, but I suspect poorly.
I would always stick to a simple includes and in-Ruby filter before attempting to optimize with SQL.

Returning a result when sql query finds no matches

I am pulling a userid from a database named people and have given it a variable of $userid. That same userid is associated with another table named info, sometimes. Sometimes there is a matching userid, sometimes that userid is not associated with the info table. When I do the following query, the function is skipped when the userid in the people table does not have a matching userid in the info table. Is there a way to get a result back when no match is found?
$club_query = $wpdb->get_results( $wpdb->prepare("SELECT clubs FROM info WHERE userid = '$userid' LIMIT 1") );
If the club is in the results, then perform a function.
Any help is appreciated.
There are a few dirty hacks I've used for this sort of thing. One is to use MIN(clubs) instead of clubs, since if there are no rows, then MIN(...) returns NULL:
SELECT MIN(clubs) clubs FROM info WHERE userid = ...
Another is to use a RIGHT JOIN (SELECT 1) t:
SELECT info.clubs FROM info RIGHT JOIN (SELECT 1) t ON info.userid = ...
Both approaches work, but have some drawbacks/limitations.
Edited to add: another approach that just occurred to me right now is to use a subquery in the field-list:
SELECT (SELECT clubs FROM info WHERE userid = ...) clubs;
which also converts an empty result-set into NULL. This, too, has some limitations.

Update values in each row based on foreign_key value

Downloads table:
id (primary key)
user_id
item_id
created_at
updated_at
The user_id and item_id in this case are both incorrect, however, they're properly stored in the users and items table, respectively (import_id for in each table). Here's what I'm trying to script:
downloads.each do |download|
user = User.find_by_import_id(download.user_id)
item = item.find_by_import_id(download.item_id)
if user && item
download.update_attributes(:user_id => user.id, :item.id => item.id)
end
end
So,
look up the user and item based on
their respective "import_id"'s. Then
update those values in the download record
This takes forever with a ton of rows. Anyway to do this in SQL?
If I understand you correctly, you simply need to add two sub-querys in your SELECT statement to lookup the correct IDs. For example:
SELECT id,
(SELECT correct_id FROM User WHERE import_id=user_id) AS UserID,
(SELECT correct_id FROM Item WHERE import_id=item_id) AS ItemID,
created_at,
updated_at
FROM Downloads
This will translate your incorrect user_ids to whatever ID you want to come from the User table and it will do the same for your item_ids. The information coming from SQL will now be correct.
If, however, you want to update the tables with the correct information, you could write this like so:
UPDATE Downloads
SET user_id = User.user_id,
item_id = Item.item_id
FROM Downloads
INNER JOIN User ON Downloads.user_id = User.import_id
INNER JOIN Item ON Downloads.item_id = Item.import_id
WHERE ...
Make sure to put something in the WHERE clause so you don't update every record in the Downloads table (unless that is the plan). I rewrote the above statement to be a bit more optimized since the original version had two SELECT statements per row, which is a bit intense.
Edit:
Since this is PostgreSQL, you can't have the table name in both the UPDATE and the FROM section. Instead, the tables in the FROM section are joined to the table being updated. Here is a quote about this from the PostgreSQL website:
When a FROM clause is present, what essentially happens is that the target table is joined to the tables mentioned in the fromlist, and each output row of the join represents an update operation for the target table. When using FROM you should ensure that the join produces at most one output row for each row to be modified. In other words, a target row shouldn't join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable.
http://www.postgresql.org/docs/8.1/static/sql-update.html
With this in mind, here is an example that I think should work (can't test it, sorry):
UPDATE Downloads
SET user_id = User.user_id,
item_id = Item.item_id
FROM User, Item
WHERE Downloads.user_id = User.import_id AND
Downloads.item_id = Item.import_id
That is the basic idea. Don't forget you will still need to add extra criteria to the WHERE section to limit the rows that are updated.
i'm totally guessing from your question, but you have some kind of lookup table that will match an import user_id with the real user_id, and similarly from items. i.e. the assumption is your line of code:
User.find_by_import_id(download.user_id)
hits the database to do the lookup. the import_users / import_items tables are just the names i've given to the lookup tables to do this.
UPDATE downloads
SET downloads.user_id = users.user_id
, downloads.item_id = items.items_id
FROM downloads
INNER JOIN import_users ON downloads.user_id = import_users.import_user_id
INNER JOIN import_items ON downloads.item_id = import_items.import_item_id
Either way (lookup is in DB, or it's derived from code), would it not just be easier to insert the information correctly in the first place? this would mean you can't have any FK's on your table since sometimes they point to one table, and others they point to another. seems a bit odd.