Link data from third table to a 1st and a 2nd table - sql

I got a little problem and I wonder if there is a solution.
Tried finding something existing, to no avail.
So here is my code :
Select
Order.AccountID,
Order.UserID,
Order.OrderID,
Order.OrderDate,
User.UserName,
Note.NoteID,
Note.UserID,
Note.NoteDate,
Note.Text
FROM
Order
INNER JOIN User ON (Order.UserID=User.UserID)
LEFT OUTER JOIN Note ON (Order.AccountID=Note.AccountID)
WHERE
Order.OrderDate >="2016-01-01"
AND
Order.OrderDate <= (current date -1 day)
AND
Note.NoteID IN (21,41,89)
AND
Note.NoteDate >="2016-01-01"
AND
Note.NoteDate<= (current date -1 day)
GROUPBY
Order.AccountID,
Order.UserID,
Order.OrderID,
Order.OrderDate,
User.UserName,
Note.UserID,
Note.NoteDate,
Note.Text
So we have 3 tables :
The Order Table : Contains Orders. They are saved with the userID who did the order.
The User Table : Has the UserIDs and the Username. I already used the table to link the usernames to the userIDs in the orders.
The Note Table : Contains notes on the account and the userID who wrote the note. I want to also get the usernames of the userIDS on the notes.
The one who did the order, is not necessary the one who wrote the note...
Question : How do I get the usernames Linked to my notes as they are already linked to my orders ?
Tables :
Order
AccountID | OrderID | OrderDate | UserID
User
UserID | Username
Note
NoteID | NoteDate | Text | UserID
Something like :
AccountID | OrderID | OrderDate | Order.UserID | Order.Username | NoteID | NoteDate | Text | UserID | Note.Username
How do ?

If I understand your question correctly, you just need to do the same as what you have already done with an alias:
Select
Order.AccountID,
Order.UserID,
Order.OrderID,
Order.OrderDate,
User.UserName,
Note.NoteID,
Note.UserID,
Note.NoteDate,
Note.Text,
NoteWriter.UserName as 'NoteWriter_Username'
FROM
INNER JOIN User ON (Order.UserID=User.UserID)
LEFT OUTER JOIN Note ON (Order.AccountID=Note.AccountID)
LEFT OUTER JOIN user NoteWriter on NoteWriter.userid = Note.userID
WHERE
Order.OrderDate >="2016-01-01"
AND Order.OrderDate <= (current date -1 day)
AND Note.NoteID IN (21,41,89)
AND Note.NoteDate >="2016-01-01"
AND Note.NoteDate<= (current date -1 day)
The trick is to alias the table you are joining on so that you can reference it. I've aliased the new join as NoteWriter, who will represent the user that added the note. I've also aliased the new column in your select, just to show you that you can name things a bit easier in your result set.
I've dropped the group by as it won't change anything. Unless you have some weird data, that is.

Related

SQL query for fetching users and common friends

I know similiar questions have been asked and answered before, I have reviewed them but still can't quite wrap my head around how to do this in my case.
I would like to create a query (I use postgreSQL) that would return users from my database filtered by name, sorted by the number of friends in common with a given user (the user sending the request).
The data structure is as follows:
I have a users table, that has a column called search_full_name which stores name + surname in the format of "ADAM SMITH". This is what I filter with.
I have a user_friends table that stores information about who is friends with whom. So I have two columns in there: user_id and friend_id . The data is symmetric, i.e. for every (1,3) there is a (3,1) entry.
So far in the friend search I was just using a query like
select * from users where users.search_full_name like '%query%'
But now, I would like to additionally order the result by the amount of friends in common with the user asking, so my query would have two inputs: query and userId.
Turns out I am not as good with sql as I thought, and I would really appreciate your help, it would be great to see some explanations too.
I imagine the desired output as:
+---------+------------------+----------------------+--+
| user_id | search_full_name | common_friends_count | |
+---------+------------------+----------------------+--+
| 45 | Adam Smith | 14 | |
| 123 | Adam Cole | 11 | |
| 12 | Adamic Kapi | 0 | |
+---------+------------------+----------------------+--+
for a query like 'Adam'
I have been trying this for a whole day now and I feel my brain has exploded.
Please help, thanks
The basic idea is a self-join. The following gets a match on users who share friends with the specified user:
select uf2.user_id, count(*) as num_friends
from user_friends uf join
user_friends uf2
on uf2.friend_id = uf.friend_id and
uf2.user_id <> uf2.user_id
where uf2.user_id = ?
group by uf2.user_id
order by count(*) desc; -- the user you care about
Ok, so after a few hours I came up with a query that works :) Here it is for future reference:
select u.id, u.search_full_name, count(uf.friend_id) as common_friend_count
from users u left join user_friends uf on (u.id = uf.user_id and uf.friend_id in (select friend_id from user_friends where user_id = ?))
where u.search_full_name like ?
group by u.search_full_name, u.id
order by common_friend_count desc;

can't join table on request

I'm having issues on table joins in a sql query. I've looked it up on SO but nothing matched my problem.
Here are the two tables:
Charge
| tache_id (int) | semaine_id (int) | login (varchar) | charge (float) |
Tache
| tache_id (int) | type_id (int) | charge (float) |
Basically, every task (Tache) has a charge attribute which represents the amount of work (in days) necessary to complete the task.
The user can then plan it on several weeks (Charge).
What I want to do is display all the tasks that haven't been completely planned, and then display (in an other window) those who are.
I thought of doing something like this:
select Tache.tache_id, Tache.charge
left join Charge on Charge.tache_id = Tache.tache_id
where sum(Charge.charge) < Tache.charge
group by Tache.tache_id
But I get a 'invalid use of group function' error
something on these lines, if tache.tache_id is unique:
select Tache.tache_id, max(Tache.charge)
from tache
left join Charge on Charge.tache_id = Tache.tache_id
group by Tache.tache_id
having sum(Charge.charge) < max(Tache.charge)
What you meant is a having clause, you can use aggregate functions in the where clause..
select Tache.tache_id, max(Tache.charge)
from Tache
left join Charge on Charge.tache_id = Tache.tache_id
group by Tache.tache_id
having sum(Charge.charge) < max(Tache.charge)

SQL Query - Join the same column twice

I'm having trouble to achieve the result I want trying join a column from a table twice.
My first table is "dbo.Sessions", which contains basic session info like the user ID, the project ID, login/logout date and times, etc.
I need to join to that the user names and project names. However, these are found in another table, but in the same column (dbo.tblObjects.Name).
Example:
+------+---------------+
| k_Id | Name |
+------+---------------+
| 1 | AgentName1 |
| 2 | ProjectNameX |
| 3 | ProjectNameY |
| 4 | AgentName2 |
| 5 | ProjectNameZ |
| 6 | AgentName3 |
+------+---------------+
To try and achieve my goal, I used two "LEFT JOIN". However, I get duplicate results in both. I'll either get both columns to display either the project names or the user names (depending on which "LEFT JOIN" is first).
This is what I have at this point:
SELECT SysDB.dbo.Sessions.*, SysDB.dbo.tblObjects.Name AS AgentName, SysDB.dbo.tblObjects.Name AS ProjectName
FROM SysDB.dbo.Sessions
LEFT JOIN SysDB.dbo.tblObjects ON SysDB.dbo.Sessions.userId = SysDB.dbo.Objects.k_Id
LEFT JOIN SysDB.dbo.tblObjects ON SysDB.dbo.Sessions.projectId = SysDB.dbo.Objects.k_Id
WHERE (SysDB.dbo.Sessions.loginDate BETWEEN 'm/d/yyyy' AND 'm/d/yyyy')
Note: SysDB is the name of the database that I identify every time because this query is to be run externally. I also don't use "USE SysDB" before my selection because it doesn't work from the VBA macro this will run from.
Note 2: I have found a thread on this site that addresses this exact issue, but I can't understand what is being done, and it dates back in 2012. Something about aliases. The solution offers to add "ls." and "lt." before the table names, but that doesn't work for me. Says the table doesn't exist.
SQL Query Join Same Column Twice
Note 3: I have tried many different things, such as:
LEFT JOIN SysDB.dbo.tblObjects AS AgentName ON SysDB.dbo.Sessions.userId = SysDB.dbo.tblObjects.k_Id
LEFT JOIN SysDB.dbo.tblObjects AS ProjectName ON SysDB.dbo.Sessions.projectId = SysDB.dbo.tblObjects.k_Id
Any insights would be greatly appreciated. Thanks!
You may find it much easier to see what you are doing by giving each table an alias (session, agent, project below)
SELECT session.*, agent.Name AS AgentName, project.Name AS ProjectName
FROM SysDB.dbo.Sessions session
LEFT JOIN SysDB.dbo.tblObjects agent
ON session.userId = agent.k_Id
LEFT JOIN SysDB.dbo.tblObjects project
ON project.projectId = session.k_Id
WHERE (session.loginDate BETWEEN 'm/d/yyyy' AND 'm/d/yyyy')

SQL query - joins + counting

Here's my problem: I have a query that joins multiple tables to show details of some orders. The query result in a table with columns:
order ID | name | count | price | location | date
It's a hospital database and what i want to do is to add another column that says how many patients were at that location at given date.
There's another table that shows patient stays - I need to count those.
patient ID | location | dateFrom | dateTo
The thing is that the STAYS table shows 2 dates - FROM and TO so I need to count every patient that was present at given location (ward) when order was placed.
Here's the initial query I need to update:
SELECT
AP_ZAMPOZ.ID_TOW AS IDTowaru, --merchandiseID
GMSL_TOW.NAZWA_TOW AS Nazwa, --name
GMSL_TOW.MNOZNIK_SYN AS Mnoznik, --quantity
AP_ZAMPOZ.ZAM_CENA_S AS Cena, --price
AP_ZAMPOZ.ZAM_IL AS Ilosc, --count
AP_ZAMNAG.ZAM_DATE AS DataZam, --date
GMSL_MAG.NAZWA_MAG AS Magazyn, --location
APSL_TOW_PROD.PROD_NAZWA AS Producent, --producer
APSL_TOW_ATC.NAZWA AS Grupa -group
FROM
AP_ZAMPOZ
JOIN
GMSL_TOW ON AP_ZAMPOZ.ID_TOW = GMSL_TOW.ID_TOW
JOIN
AP_ZAMNAG ON AP_ZAMNAG.ZAM_ID_NAG = AP_ZAMPOZ.ZAM_ID_NAG
JOIN
GMSL_MAG ON AP_ZAMNAG.ID_MAG = GMSL_MAG.ID_MAG
JOIN
APSL_TOW ON AP_ZAMPOZ.ID_TOW = APSL_TOW.ID_TOW
LEFT JOIN
APSL_TOW_PROD ON APSL_TOW.ID_PROD = APSL_TOW_PROD.ID_PROD
LEFT JOIN
APSL_TOW_ATC ON APSL_TOW.KOD = APSL_TOW_ATC.KOD
The table with stays is called POBYT and has these relevant columns:
| ID_POB (ID) | IDK_JOS (location identifier) | DT_OD (date From) | DT_TO (date To)
Rows that I would like to see should look like those in my present query + number of patients at given location at given date.
Anyone have any ideas how to achieve this? I'm stuck...
problem solved by adding subquery as another SELECT column.
Heres the code
SELECT
.
.
.
APSL_TOW_ATC.NAZWA AS Grupa
(SELECT Count(*)
FROM pobyt
WHERE (TO_DATE( AP_ZAMNAG.ZAM_DATE, 'YY/MM/DD') >= TO_DATE(DT_OD, 'YY-MM-DD') AND (TO_DATE( AP_ZAMNAG.ZAM_DATE, 'YY/MM/DD') <= TO_DATE(DT_DO, 'YY-MM-DD') OR dt_do IS NULL))
AND IDK_JOS = GMSL_MAG.KOD_MAG) AS LiczbaPacjentow --no. of patients at given date
FROM AP_ZAMPOZ
.
.
.
Works great.

Access join on first record

I have two tables in an Access database, tblProducts and tblProductGroups.
I am trying to run a query that joins both of these tables, and brings back a single record for each product. The problem is that the current design allows for a product to be listed in the tblProductGroups table more than 1 - i.e. a product can be a member of more than one group (i didnt design this!)
The query is this:
select tblProducts.intID, tblProducts.strTitle, tblProductGroups.intGroup
from tblProducts
inner join tblProductGroups on tblProducts.intID = tblProductGroups.intProduct
where tblProductGroups.intGroup = 56
and tblProducts.blnActive
order by tblProducts.intSort asc, tblProducts.curPrice asc
At the moment this returns results such as:
intID | strTitle | intGroup
1 | Product 1 | 1
1 | Product 1 | 2
2 | Product 2 | 1
2 | Product 2 | 2
Whereas I only want the join to be based on the first matching record, so that would return:
intID | strTitle | intGroup
1 | Product 1 | 1
2 | Product 2 | 1
Is this possible in Access?
Thanks in advance
Al
This option runs a subquery to find the minimum intGoup for each tblProducts.intID.
SELECT tblProducts.intID
, tblProducts.strTitle
, (SELECT TOP 1 intGroup
FROM tblProductGroups
WHERE intProduct=tblProducts.intID
ORDER BY intGroup ASC) AS intGroup
FROM tblProducts
WHERE tblProducts.blnActive
ORDER BY tblProducts.intSort ASC, tblProducts.curPrice ASC
This works for me. Maybe this helps someone:
SELECT
a.Lagerort_ID,
FIRST(a.Regal) AS frstRegal,
FIRST(a.Fachboden) AS frstFachboden,
FIRST(a.xOffset) AS frstxOffset,
FIRST(a.yOffset) AS frstyOffset,
FIRST(a.xSize) AS frstxSize,
FIRST(a.ySize) AS frstySize,
FIRST(a.Platzgr) AS frstyPlatzgr,
FIRST(b.Artikel_ID) AS frstArtikel_ID,
FIRST(b.Menge) AS frstMenge,
FIRST(c.Breite) AS frstBreite,
FIRST(c.Tiefe) AS frstTiefe,
FIRST(a.Fachboden_ID) AS frstFachboden_ID,
FIRST(b.BewegungsDatum) AS frstBewegungsDatum,
FIRST(b.ErzeugungsDatum) AS frstErzeugungsDatum
FROM ((Lagerort AS a)
LEFT JOIN LO_zu_ART AS b ON a.Lagerort_ID = b.Lagerort_ID)
LEFT JOIN Regal AS c ON a.Regal = c.Regal
GROUP BY a.Lagerort_ID
ORDER BY FIRST(a.Regal), FIRST(a.Fachboden), FIRST(a.xOffset), FIRST(a.yOffset);
I have non unique entries for Lagerort_ID on the table LO_zu_ART. My goal was to only use the first found entry from LO_zu_ART to match into Lagerort.
The trick is to use FIRST() an any column but the grouped one. This may also work with MIN() or MAX(), but I have not tested it.
Also make sure to call the Fields with the "AS" statement different than the original field. I used frstFIELDNAME. This is important, otherwise I got errors.
Create a new query, qryFirstGroupPerProduct:
SELECT intProduct, Min(intGroup) AS lowest_group
FROM tblProductGroups
GROUP BY intProduct;
Then JOIN qryFirstGroupPerProduct (instead of tblProductsGroups) to tblProducts.
Or you could do it as a subquery instead of a separate saved query, if you prefer.
It's not very optimal, but if you're bringing in a few thousand records this will work:
Create a query that gets the max of tblProducts.intID from one table and call it qry_Temp.
Create another query and join qry_temp to the table you are trying to join against, and you should get your results.