Trying to display id of table 1 as it relates to table 3 - sql

I have three tables: exfillocation, phishkit, snapshot. We need to be able to query exfillocation.filename and print the related snapshot.id, which requires traversing the phishkit table.
exfillocation.phishkit_id is related to phishkit.id as a foreign key.
Table exfillocation schema:
id exfil_location phishkit_id
== ========= ============
1 ['open.txt'] 7442
2 ['bot.txt'] 9931
phishkit.snapshot_id is related to snapshot.id as a foreign key.
Phishkit schema:
id snapshot_id md5
=== ============ =====
7442 1492 f4a3954e39b90c02f4a3954e39b90c02
9931 1661 e048f240ad0845b50abe8df9124ce3fb
Snapshot schema:
id asn url
=== ====== =============
1661 123 badwebsite.malicious.com
1492 31 haxx0rs.hacking.com
I've tried reading postgresql's four different JOIN methods as well as the UNION method, but I don't seem to get the snapshot_id column returned.
I tried something awkward this this:
SELECT exfil_location, found_in_file, phishkit_id
FROM public.lookup_exfillocation
FULL OUTER JOIN public.lookup_phishkit
ON public.lookup_exfillocation.phishkit_id = public.lookup_phishkit.id
FULL OUTER JOIN public.lookup_snapshot
ON public.lookup_phishkit.snapshot_id = public.lookup_snapshot.id WHERE exfil_location::text NOT LIKE ('__script.txt__') ORDER BY phishkit_id;
I expected to see the related lookup_snapshot.id and the related lookup_phishkit.id, which neither showed.

I accidentally found the solution. It came down to what columns I was SELECTing. Using a * showed all columns in the JOIN statements. Then I picked from the columns needed. The query looks like:
FROM public.lookup_exfillocation
FULL OUTER JOIN public.lookup_phishkit
ON public.lookup_exfillocation.phishkit_id = public.lookup_phishkit.id
FULL OUTER JOIN public.lookup_snapshot
ON public.lookup_phishkit.snapshot_id = public.lookup_snapshot.id WHERE exfil_location::text NOT LIKE ('__script.txt__') ORDER BY phishkit_id;```

Related

Aliases for 2 joins on one table in Microsoft Access

I have a table that shows relationships between items and another table with the items themselves:
articles_to_articles
-------------------------
|articleID_1|articleID_2|
-------------------------
|12345 |67890 |
|23442 |343243 |
-------------------------
articles
-----------------------------------------------------
|article_id | article_name|lots | of | other | stuff|
-----------------------------------------------------
I am attempting to generate a file with that consists of the relationships from articles_to_articles but with the names in addition to the ids.
What I have so far is:
SELECT
a2a.articleID_1,
key_articles.article_name,
a2a.articleID_2,
val_articles.article_name
FROM
articles_to_articles a2a
INNER JOIN
articles key_articles
ON key_articles.articleID = articles_to_articles.articleID_1
INNER JOIN
articles val_articles
ON val_articles.articleID = articles_to_articles.articleID_2;
Access gives me a "missing operator" error but I can't seem to find the missing operator. What basic thing am I missing?
When joining more than two tables in MS Access, you must enclose each join within separate groups of parentheses, for example:
SELECT
a2a.articleID_1,
key_articles.article_name,
a2a.articleID_2,
val_articles.article_name
FROM
(
articles_to_articles a2a
INNER JOIN
articles key_articles
ON
key_articles.articleID = a2a.articleID_1
)
INNER JOIN
articles val_articles
ON
val_articles.articleID = a2a.articleID_2

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')

INNER JOIN on broken table (non-nullable field)

I have three tables:
Document DocumentExt Tracking
------------------------- ----------------- --------------------------------------------
ID | Name | DocType DocId | OtherId ID | DocOtherId | DocType | AccessTime
------------------------- ----------------- --------------------------------------------
1 SomeDoc Z 1 Doc1 1 Doc2 X [Date here]
2 SomeDoc2 X 2 Doc2 2 A [Date here]
3 SomeDoc3 Y 3 Doc3 3 Doc1 Z [Date here]
... ... ... ... ... ... ... ... ...
Note the missing value in Tracking.DocOtherId. This is a non-nullable field and defaults to an empty string.
The problem is that I need to perform a join on these two that includes one row for each record in Tracking, but also the associated information from Document. Such like:
SELECT
Tracking.ID, Document.Name
FROM
Tracking
INNER JOIN
DocumentExt ON DocumentExt.OtherId = Tracking.DocOtherId
INNER JOIN
Document ON Document.ID = DocumentExt.DocId
However, since Tracking.DocOtherId in non-nullable, the query is returning a row for each of the records in DocumentExt AND Tracking. I need it to treat Tracking.DocOtherId as nullable for the purposes of the query so that the JOIN will work properly. Is there a way to do this?
EDIT: I suppose I need to make it clear that I need ONE record returned for EACH record in Tracking, including the ones with the empty string in DocOtherId.
For example:
TrackingId | DocumentName
---------------------------
1 SomeDoc2
2 NULL
3 SomeDoc1
... ...
EDIT 2: Flagged for closure. I went about this all wrong and I've taken an entirely different approach.
If your data is not significantly large, you can try using a temp table to strip your data and then do a join on that refined data. For example:
EDIT: to respond to the first comment below
this first section will get you the temp table you need without the empty strings and instead have nulls where the empty strings would be
Select ID,
case when DocOtherId = '' then null else DocOtherId end,
AccessTime
into #tracking
From Tracking
then use this temp table to join back to your data the same way you had originally. in this example you just sub out #tracking for Tracking, though you can call your temp table anything you want.
SELECT
Tracking.ID, Document.Name
FROM
#tracking
INNER JOIN
DocumentExt ON DocumentExt.OtherId = Tracking.DocOtherId
INNER JOIN
Document ON Document.ID = DocumentExt.DocId
I saw this comment:
I need ALL of the records from Tracking included.
That means you want an OUTER join, not an INNER join. Use the coalesce() function to show a generic value for missing names.
SELECT Tracking.ID, coalesce(Document.Name,'') As Name
FROM Tracking t
LEFT JOIN DocumentExt de ON de.OtherID = t.DocOtherId
LEFT JOIN Document d on d.ID = de.DocID
This will return ONE record for EACH record in the tracking table, including the ones with the empty string in DocOtherId.

sybase - values from one table that aren't on another, on opposite ends of a 3-table join

Hypothetical situation: I work for a custom sign-making company, and some of our clients have submitted more sign designs than they're currently using. I want to know what signs have never been used.
3 tables involved:
table A - signs for a company
sign_pk(unique) | company_pk | sign_description
1 --------------------1 ---------------- small
2 --------------------1 ---------------- large
3 --------------------2 ---------------- medium
4 --------------------2 ---------------- jumbo
5 --------------------3 ---------------- banner
table B - company locations
company_pk | company_location(unique)
1 ------|------ 987
1 ------|------ 876
2 ------|------ 456
2 ------|------ 123
table C - signs at locations (it's a bit of a stretch, but each row can have 2 signs, and it's a one to many relationship from company location to signs at locations)
company_location | front_sign | back_sign
987 ------------ 1 ------------ 2
987 ------------ 2 ------------ 1
876 ------------ 2 ------------ 1
456 ------------ 3 ------------ 4
123 ------------ 4 ------------ 3
So, a.company_pk = b.company_pk and b.company_location = c.company_location. What I want to try and find is how to query and get back that sign_pk 5 isn't at any location. Querying each sign_pk against all of the front_sign and back_sign values is a little impractical, since all the tables have millions of rows. Table a is indexed on sign_pk and company_pk, table b on both fields, and table c only on company locations. The way I'm trying to write it is along the lines of "each sign belongs to a company, so find the signs that are not the front or back sign at any of the locations that belong to the company tied to that sign."
My original plan was:
Select a.sign_pk
from a, b, c
where a.company_pk = b.company_pk
and b.company_location = c.company_location
and a.sign_pk *= c.front_sign
group by a.sign_pk having count(c.front_sign) = 0
just to do the front sign, and then repeat for the back, but that won't run because c is an inner member of an outer join, and also in an inner join.
This whole thing is fairly convoluted, but if anyone can make sense of it, I'll be your best friend.
How about something like this:
SELECT DISTINCT sign_pk
FROM table_a
WHERE sign_pk NOT IN
(
SELECT DISTINCT front_sign sign
FROM table_c
UNION
SELECT DISTINCT rear_sign sign
FROM table_c
)
ANSI outer join is your friend here. *= has dodgy semantics and should be avoided
select distinct a.sign_pk, a.company_pk
from a join b on a.company_pk = b.company_pk
left outer join c on b.company_location = c.company_location
and (a.sign_pk = c.front_sign or a.sign_pk = c.back_sign)
where c.company_location is null
Note that the where clause is a filter on the rows returned by the join, so it says "do the joins, but give me only the rows that didn't to join to c"
Outer join is almost always faster than NOT EXISTS and NOT IN
I would be tempted to create a Temp table for the inner join and then outer join that.
But it really depends on the size of your data sets.
Yes, the schema design is flawed, but we can't always fix that!

Creating new table from data of other tables

I'm very new to SQL and I hope someone can help me with some SQL syntax. I have a database with these tables and fields,
DATA: data_id, person_id, attribute_id, date, value
PERSONS: person_id, parent_id, name
ATTRIBUTES: attribute_id, attribute_type
attribute_type can be "Height" or "Weight"
Question 1
Give a person's "Name", I would like to return a table of "Weight" measurements for each children. Ie: if John has 3 children names Alice, Bob and Carol, then I want a table like this
| date | Alice | Bob | Carol |
I know how to get a long list of children's weights like this:
select d.date,
d.value
from data d,
persons child,
persons parent,
attributes a
where parent.name='John'
and child.parent_id = parent.person_id
and d.attribute_id = a.attribute_id
and a.attribute_type = "Weight';
but I don't know how to create a new table that looks like:
| date | Child 1 name | Child 2 name | ... | Child N name |
Question 2
Also, I would like to select the attributes to be between a certain range.
Question 3
What happens if the dates are not consistent across the children? For example, suppose Alice is 3 years older than Bob, then there's no data for Bob during the first 3 years of Alice's life. How does the database handle this if we request all the data?
1) It might not be so easy. MS SQL Server can PIVOT a table on an axis, but dumping the resultset to an array and sorting there (assuming this is tied to some sort of program) might be the simpler way right now if you're new to SQL.
If you can manage to do it in SQL it still won't be enough info to create a new table, just return the data you'd use to fill it in, so some sort of external manipulation will probably be required. But you can probably just use INSERT INTO [new table] SELECT [...] to fill that new table from your select query, at least.
2) You can join on attributes for each unique attribute:
SELECT [...] FROM data AS d
JOIN persons AS p ON d.person_id = p.person_id
JOIN attributes AS weight ON p.attribute_id = weight.attribute_id
HAVING weight.attribute_type = 'Weight'
JOIN attributes AS height ON p.attribute_id = height.attribute_id
HAVING height.attribute_type = 'Height'
[...]
(The way you're joining in the original query is just shorthand for [INNER] JOIN .. ON, same thing except you'll need the HAVING clause in there)
3) It depends on the type of JOIN you use to match parent/child relationships, and any dates you're filtering on in the WHERE, if I'm reading that right (entirely possible I'm not). I'm not sure quite what you're looking for, or what kind of database you're using, so no good answer. If you're new enough to SQL that you don't know the different kinds of JOINs and what they can do, it's very worthwhile to learn them - they put the R in RDBMS.
when you do a select, you need to specify the exact columns you want. In other words you can't return the Nth child's name. Ie this isn't possible:
1/2/2010 | Child_1_name | Child_2_name | Child_3_name
1/3/2010 | Child_1_name
1/4/2010 | Child_1_name | Child_2_name
Each record needs to have the same amount of columns. So you might be able to make a select that does this:
1/2/2010 | Child_1_name
1/2/2010 | Child_2_name
1/2/2010 | Child_3_name
1/3/2010 | Child_1_name
1/4/2010 | Child_1_name
1/4/2010 | Child_2_name
And then in a report remap it to how you want it displayed