List manipulating data from two tables content - sql

I have these two tables
I would like to know how to do to list the product table: ProdID, Quantity, Name, Price
and table productUser: userId, State
The problem is that I need to also list all the information of product table and adding the UserId field with the same value and the state looks for a default value would be false ..
It is possible? could also, not to add the userId, State and drive it from my application code for assigning values​​. thanks
UPDATE:

If I understand your question correctly, you want to list specific fields from both tables but only when the child records match your criteria. If so, the query below would allow you to specify the userID and State.
SELECT p.prodId
,p.Quantity
,p.Name
,p.Price
,pu.userId
,pu.State
FROM Product p
INNER JOIN ProductUser pu
ON p.prodId = pu.prodId
WHERE pu.userID = #userID
AND pu.State = 0
--AND pu.State = #State
If my understanding is not correct, please post some sample table data and indicate which results you want returned.
Update to your update: I've defaulted State to zero in the query above. Followup question: do you want columns from both tables or are you trying to do an existence check against ProductUser to return just columns from Product?

Related

Join 2 tables based on column name present in a table row

I have a table called Target where I have 5 columns:
ProductLevel
ProductName
CustomerLevel
CustomerName
Target
In another table called Products I have 3 columns:
ProductId
ProductCategory
ProductBrand
In the 3rd table called Customer I have 3 columns:
CustomerID
CustomerName
SubCustomerName
Is there a way to do a dynamic join where I select the column I will use in the JOIN based on the value that I have in the 1st table?
Example: If in the first table I have Category in ProductLevel, I'll join the table product using ProductCategory field. If I have Brand, I'll join using ProductBrand... The same happens with Customer table.
PS: I'm looking for a way to create it dynamically in a way I can add new columns to that tables without changing my code, then in the future I can have ProductSegment column in Product Table and Segment as a value in ProductLevel in Target table.
Yes, like this:
SELECT * FROM
Target t
INNER JOIN
Product p
ON
(t.ProductLevel = 'Category' AND t.??? = p.ProductCategory)
OR
(t.ProductLevel = 'Brand' AND t.??? = p.ProductBrand)
You didn't say which column in Target holds your product category/brand hence the ??? in the query above. Replace ??? with something sensible
PS; you can't do as you ask in your PS, and even this structure above is an indicator that your data model is broken. You can at least put the code in for it now even if there are no rows with t.ProductLevel = 'Segment'
Don't expect this to perform well or scale.. You might be able to improve performance by doing it as a set of UNION queries rather than OR, but you may run into issues where indexes aren't used, crippling performance

In SQL Server, how can I change a column values depending on whether it contains a certain value?

Sorry if the title is a bit confusing... I'm trying to fix some data. Here goes the explanation:
Say I have two tables.
The first is a lookup table that is no longer in use.
The second has one varchar(50) column that sometimes has product names and
sometimes has product ids from the old lookup table.
The idea is to convert all the PID values in the Product table into the product names. Here's a pic i made up to help illustrate it:
The lookup table is much larger, that's just an example. So i'd guess it would be an update statement that would use the ProductsLookup.Name value if the Product value was found to be in the ProductsLookup.PID set? How would this look in SQL?
Thanks much for the help,
Carlos
You need to put inner join with both these tables "ProductsLookup" and "Products" on PID and Product column. But Product column in "Products" table is varchar so you have to apply ISNUMERIC function on this column to make sure that join works fine. below is example
UPDATE
P
SET
P.Product=PL.Name
FROM
Products P
INNER JOIN ProductsLookup PL ON PL.PID=CASE WHEN ISNUMERIC(P.Product)=1 THEN P.Product ELSE -1 END
You can do this with an update and join:
update p
set product = pl.name
from products p join
productslookup pl
on pl.pid = p.id;
A left join is not needed, because you only need to update the values that match in the lookup table.
I will caution you that performance might be an issue. The problem is the types between the two tables -- presumably pid is a number not a string. If so, you can create a computed column to change the type and an index on that column.

A table to hold History of changes for two fields

I have a table which holds a Person (details). Two of the fields, we have a requirement to store and show the history of the changes. They are 'IsActive BIT' and 'IsIdle BIT'.
At the moment, they're fields within the Person table.
The requirement is to be able to display when the person was active, and when they were idle. As well as who set those values. (All tales have a LastUpdatedBy and CreatedBy column).
My plan is to use a PersonHistory table, with the PersonID FK to the Person, and the IsActive and IsIdle columns, and the CreatedBy and LastUpdatedBy columns. And a 'EffectiveFrom' DATETIME.
So when we create a person, we add a row to the history with the IsActive and IsIdle values, user and the PersonID.
To display a person, we have to do an (Untidy?) selection of the person record, and then join to the last record for that person in the history table. INNER JOIN .. SELECT TOP 1 * FROM History, using a ROW_NUMBER? Might be slow.
When editing 'IsActive', we need to add a new row with the PersonID and the new IsActive (and/or IsIdle) value. Actually, we need to store both. A row will only get written when these values change. Which means we'll need to do a pre-save check to see if the values changed.
Does this seem like a standard way to handle this requirement - or is there a better more common approach?
You might try this method before changing the data structure:
select p.*, ph.*
from Person p outer apply
(select top 1 ph.*
from personhistory ph
where ph.personid = p.personid
order by ph.effectivefrom desc
) ph;
For performance, you want an index on personhistory(personid, effetivefrom).

Querying records that meet muliple criteria

Hi I’m trying to write a query and I’m struggling to figure out how to go about it.
I have a suppliers table and a supplier parts table I want to write a query that lists suppliers that have specified related Parts in the supplier parts table. If a supplier doesn’t have all specified related parts then they should not be listed.
At the moment I have written a very basic query that lists the supplier if they have a related supplier part that meets the criteria.
SELECT id ,name
FROM
efacdb.dbo.suppliers INNER JOIN [efacdb].[dbo].[spmatrix] ON
id = spmsupp
WHERE spmpart
IN ('ALUM_5083', 'ALUM_6082')
I only want to show the supplier if they have both parts related. Does anyone know how I could do this?
Use a subquery with counting distinct occurences:
select * from suppliers s
where 2 = (select count(distinct spmpart) from spmatrix
where id = spmsupp and spmpart in ('ALUM_5083', 'ALUM_6082'))
As a note, you can modify your query to get what you want, just by using an aggregation:
SELECT id, name
FROM efacdb.dbo.suppliers INNER JOIN
[efacdb].[dbo].[spmatrix]
ON id = spmsupp
WHERE spmpart IN ('ALUM_5083', 'ALUM_6082')
GROUP BY id, name
HAVING MIN(spmpart) <> MAX(spmpart);
If you know there are no duplicates, then having count(*) = 2 also solves the problem.

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.