Getting values from 3 tables where two of those are self-joined - sql

Problem Introduction:
I'm working on a faker e-banking system as a side project for practicing my SQL skills (which are super bad), and I'm now stuck at a point where I want to pull data from two tables but cannot do that with joins
So, basically I have a users table which looks like this:
And I have a transactions table which saves the sender id, receiver id, amount, and date. And it looks like this:
What I want to achieve:
Now, I want to create a query that extracts the data in the transactions table in a way such that if I specified an ID of n (somewhere in the query), I'd get all of the transactions that user with ID of n made in a way that it displays the first name of both sender and receiver of all of theses transactions.
I've been doing a lot of joins/subquery stuff to extract that information but I really can't seem to find a solution.
I'm using PostgreSQL btw.
Notes:
Sender & Receiver are not the same person
I want to display the first name of both the sender & receiver

You can achieve this by joining to the users table twice (you'll have to give it a separate name for each join). The following snippet leaves out some detail but illustrates the idea -
SELECT
...
FROM
transactions t
INNER JOIN users s ON t.sender = s.id
INNER JOIN users r ON t.receiver = r.id

in the transaction table I understand that the sender and receiver columns are the ids of the customers in the users table.
Filter all the transactions in which a jane user with id 17 has received a transaction (for simplicity I will use *, but ideally you should select the columns you need)
select * from users, transactions where users.id=transactions.receiver and users.id='17'.
the same but for jane shipments
select * from users, transactions where users.id=transactions.sender and users.id='17'.
if you want all the jane transactions
select * from users, transactions where users.id=transactions.receiver and users.id=transactions.sender and users.id='17'.
if you want to further filter by an amount of money sent
select * from users, transactions where users.id=transactions.sender and users.id='17' and amount > 100
finally
select first_name from users, transactions where users.id=transactions.receiver and users.id=transactions.sender and (users.id='17' or users.id='18' )
finally finally
select first_name from users, transactions where users.id=transactions.receiver and users.id=transactions.sender

Related

How to tightly contain an SQL query result

I'm writing an application that implements a message system through a 'memos' table in a database. The table has several fields that look like this:
id, date_sent, subject, senderid, recipients,message, status
When someone sends a new memo, it will be entered into the memos table. A memo can be sent to multiple people at the same time and the recipients userid's will be inserted into the 'recipients' field as comma separated values.
It would seem that an SQL query like this would work to see if a specific userid is included in a memo:
SELECT * FROM memos WHERE recipients LIKE %15%
But I'm not sure this is the right solution. If I use the SQL statement above, won't that return everything that "contains" 15? For example, using the above statement, user 15, 1550, 1564, 2015, would all be included in the result set (and those users might not actually be on the recipient list).
What is the best way to resolve this so that ONLY the user 15 is pulled in if they are in the recipient field instead of everything containing a 15? Am I misunderstanding the LIKE statement?
I think you would be better off having your recipients as a child table of the memos table. So your memo's table has a memo ID which is referenced by the child table as
MemoRecipients
-----
MemoRecipientId INT PRIMARY KEY, IDENTITY,
MemoId INT FK to memos NOT NULL
UserId INT NOT NULL
for querying specific memos from a user you would do something like
SELECT *
FROM MEMOS m
INNER JOIN memoRecipients mr on m.Id = mr.memoId
WHERE userId = 15
No, you aren't misunderstood, that's how LIKE works.. But to achieve what you want, it would be better not to combine the recipients into 1 field. Instead try to create separate table that saves the recipient list for each memo..
For me I will use below schema, for your need:
Table_Memo
id, date_sent, subject, senderid, message, status
Table_Recipient
id_memo FK Table_Memo(id), recipient
By doing so, if you want to get specific recipients from a memo, you can do such query:
SELECT a.* FROM Table_Memo a, Table_Recipient b
WHERE a.id = "memo_id" AND a.id = b.id_memo AND b.recipient LIKE %15%
I am not sure how your application is exactly pulling these messages, but I imagine that better way would be creating a table message_recepient, which will represent many-to-many relationship between recipients and memos
id, memoId, recepientId
Then your application could pull messages like this
SELECT m.*
FROM memos m inner join message_recepient mr on m.id = mr.memoId
WHERE recepientId = 15
This way you will get messages for the specific user. Again, don't know what your status field is for but if this is for new/read/unread, you could add in your where
and m.status = 'new'
Order by date_set desc
This way you could just accumulate messages, those that are new

SQL Server Select data excluding Junction table

i need to select data that is not present in the junction table
so got three tables
trialsTable (trialID,TrialName)
VolunteerTAble(volunteerID, VolunteerName)
JunctionTAble(JunctionTableIs,TrialID,VolunteerName)
for every trial an email is sent to volunteers, but next time i want to exclude the volunteers which have received email for that trial and only send email to volunteers which have not received email for that trial, hence i created the junction table which have many to many relationship for the trial and volunteers
Assuming you have a variable or something for the #TrialId which you currently want something like:
SELECT *
FROM VolunteerTable v
WHERE NOT EXISTS(SELECT 1
FROM JunctionTable j
WHERE j.VolunteerName = v.VolunteerName
AND j.TrialID = #TrialId)
And you should probably put volunteerID in you juntion table instead of name.

SQL with nested joins and sums

Hoping someone can give me a little bit of help with a query that I'm stuck on.
Using MS-Sql server 2012
This is part of a larger query but for the purposes of my questions I'm only concerned with 4 tables: Account, user, product, productstats
And a simplified layout of each table is as follows:
account: id, parentaccountID, name
user: id, accountID, email
product: id, accountID
productstats: id, productID, views
So user links to the account table and the account table can link to itself with the parentaccountID field. Product table links to the user table and the productstats table links to the product table.
The productstats contains statistics on each product. In my example above we have how many times someone has viewed a product.
I want to get the sum of all product views under each parent account, including it's child accounts. However, when people search for an account they can search either via account.name or user.email
so if they search by user.email, i want to include all products from that users account, and any child or parent account(s) that it's part of.
One note - the parent/child account structure is only 1 level deep. Meaning an account is either the parent or the child, it's never both. parent accounts have a null value for ParentAccountID.
SELECT a2.ParentAccountID, a.id, a.Name, SUM(ps.PageViews)
FROM account a
LEFT JOIN account a2 ON a.id = a2.ParentAccountID
LEFT JOIN product p ON a.id = p.AccountID OR p.AccountID = a2.ID
LEFT JOIN ProductStatistic ps ON p.id = ps.ProductID
WHERE a.ame LIKE 'test'
GROUP BY a.id, a2.ParentAccountID, a.DealerName
That's a simplified version of the query - I haven't even included the user table yet since i haven't gotten it working this far yet.
The values I get back on that query are:
ParentAccountID =4, ID =4, name=test, sum=1617
When I run the following query
SELECT SUM(pageviews) FROM ProductStatistic WHERE ProductID IN (
SELECT id FROM product WHERE AccountID IN (4, 32, 112, 3757, 3794))
I get 453 back as the result - those account IDs are the parent account ID and it's 4 child accounts. I have no idea how it's getting 1617 since that's not even a multiple of 453
When you break up your query into some smaller parts, it will become a lot clearer.
First obtain the accounts involved
Then determine the relevant products
Only then join in the stats table to obtain the view counts
Have a look at this this sql fiddle.
[EDIT]
Added a new fiddle that adresses your comments. Not so simple no more, but I think it does what you need.

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.

how to query access to select entire records given a distinct criteria

I want to select the entire first row of each record where a promo code is unique. I am trying to create a samples table, in this table will be one record (the first record) from each distinct promo code. I have asked all of my co-workers and they usually go though the data by hand and select one from each. the problem is that the number of promo codes grows each time and the codes change. so I want to write a query that will select the first record found to have each distinct code. so for I have something like this:
SELECT DISTINCT Customer.promo1 FROM Customer AS promo;
SELECT * FROM Customer, promo
WHERE Customer.promo1 = promo.promo1;
But this obviously give the original table. I do have a ID field called AutoID in Customer.
Thanks in advance.
I'm assuming you want the first Customer.AutoId associated with each Customer.Promo
SELECT
c.*
FROM
Customer c
INNER JOIN
(
SELECT
c.promo1,
MIN(c.AutoID) AutoID
FROM
Customer c
GROUP BY
c.promo1) FirstCusomterWithPromo
ON c.AutoID = FirstCusomterWithPromo.AutoID
Something like that:
SELECT * FROM Customer
GROUP BY Customer.promo1