Glueing together relational data rows - sql

I have a sparse table structured like:
id | name | phone | account
There is no primary key or index
There are also null values. What I want is to "glue" data from different rows together, e.g.:
Given
id | name | phone | account
1 null '339-33-27' 4
null 'John' '339-33-27' 4
I want to end up with
id | name | phone | account |
1 'John' '339-33-27' 4
However, I don't know which values are missed in the table.
What are the general way to approach this kind of problem? Do I need to use only joins or might be recursive functions?
Update: Provided more clear example
id to account is many-to-many
account to name is many-to-many
phone to name is one-to-one
The database is basically raw transactional data
What I want to is to get all the rows for which I already have / could find an account

If I understand you correctly then this might work. What you need is a self join
select t2.id, t1.name, t1.phone, t1.account
from table1 t1
join table1 t2 on t1.account = t2.account and t1.phone = t2.phone
where t1.name is not null
However this particular query relies on an assumption from your example data. My assumption is that if name is not null, Id will be null and the Id can be found by looking at the phone number and account. If this assumption is not true , then we may need more sample data to solve your problem.
Depending on the data, you might need left joins or to swap so that T1 gets the id and not the name and the where condition is that ID is not null. It's hard to tell with such a small data sample size.

Related

SQL query to override content of column when matched column

Please who can help with this scenario?
I have two tables, both they have a common column ID, and Table 1 has a column Title. Normally I should update the content of this Title column for some ID, but since the table was already in use somewhere else, it wasn't a good idea to change data directly in Table 1.
That's why I created a new table table 2, which hold only the Title that must be changed associated with these ID that must be changed.
Now I am trying to get these updated titles from table 2, when there is a matching ID in table 1, otherwise show only the contents of table 1.
The result should be something like that but without using If statements.
__ID__ Title
| | | |
| | | |
You can use LEFT OUTER JOIN to this new table and COALESCE() function to say "If there is data in the new table, use it, otherwise use the data in the existing table" . Something like:
SELECT t1.id, COALESCE(t2.title, t1.title) as title
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.id;

Do a specific query for each row of a table, one by one

Let's say I have a table:
| key1 | key2 | value |
+------+------+-------+
| 1 | 1 | 1337 |
| 1 | 2 | 6545 |
| 2 | 1 | 213 |
| 3 | 1 | 131 |
What I would like to do is traverse this table row by row, then using the key two values in further queries (all other tables contain the unique combination of these two keys + other data)
How do I do this kind of thing in SQL?
EDIT: I would want to extract key1, key2 from row 1 (1,1) then do a query on it, which would result in a number.
Then I would move to the second row, an identical query which would again result in a number.
All of these numbers would be then inserted into a pre-prepared view.
EDIT2: I need to traverse it because the specific use of my database.
It is a database of planets which contains sectors (the keys are the IDs of these two). All of these sectors contain resources, turrets and walls.
The table I have in my post is an example of table of sectors, with the value being enemy force.
Table of resources, turrets etc. contain these two keys so they are linked to and only to a specific sector.
I need to go row by row so I can use this keys to select only specific resources/turrets/walls from my tables, aggregate them and then subtract them from the value in my sector table. Resulting number would then be inserted into a pre-prepared view (again, into the row which matches the combination of my two keys)
This sounds like a correlated subquery or lateral join. You don't have that much explanation, but something like this:
select t1.*, t2.*
from table1 t1 cross join lateral
(select . . .
from table2 t2 . . .
where t2.key1 = t1.key1 and t2.key2 = t1.key2
) t2
You are not clear on what the second query looks like. The where clause is called a correlation clause. It connects the subquery to the outer query. A correlation clause is not strictly needed for this to work.
The columns from the outer query can be used elsewhere in the subquery. I am just assuming that an equality condition connects the two (lacking other information).

Is chaining rows in the same table a bad pattern?

I want to create a tree structure of categories and need to find a proper way to store it into the database. Think of the following animal tree, which pretty accurately describes how it should look like:
My question now is whether chaining those entries within the same table is a good idea or not. SQLite doesn't allow me to add a FOREIGN KEY constraint to a value in the same table, so I have to make sure manually that I don't create inconsistencies. This is what I currently plan to have:
id | parent | name
---+--------+--------
1 | null | Animal
2 | 1 | Reptile
3 | 2 | Lizard
4 | 1 | Mammal
5 | 4 | Equine
6 | 4 | Bovine
parent references to an id in the same table, going up all the way until null is found, which is the root. Is this a bad pattern? And if so, what are common alternatives to put a tree structure into a relational database?
If your version of SQLite supports recursive CTE, then this is one option:
WITH RECURSIVE cte (n) AS (
SELECT id FROM yourTable WHERE parent IS NULL
UNION ALL
SELECT t1.id
FROM yourTable t1
INNER JOIN cte t2
ON t1.parent = t2.n AND t1.name NOT LIKE '%Lizard%'
)
SELECT *
FROM yourTable
WHERE id IN cte;
This is untested, but the check on t1.name in the recursive portion of the above CTE (hopefully) should stop the recursion as soon we reach a record which matches the name in the LIKE expression. In the case of searching for Lizard, the recursion should stop one level above Lizard, meaning that every record above it in the hierarchy should be returned.

SQL Show duplicate records only once in a result set

Is it possible in SQL to show duplicate records in a result only once.
So instead of this
my#email.com | Some Unique Data | Unique Data
my#email.com | Some Unique Data | Unique Data
my#email.com | Some Unique Data | Unique Data
my#email.com | Some Unique Data | Unique Data
I would get this
my#email.com | Some Unique Data | Unique Data
| Some Unique Data | Unique Data
| Some Unique Data | Unique Data
You should not be using SQL to perform presentational tasks. Any solution to do so is going to be very hacky and require cursors / some other iterative approach.
Almost every report authoring tool has a way to hide duplicates.
simply you can do this --
there are so many option or answer available for this.
one of these is as follow--
select
case
when b.c_1 = 1 then
b.col1
else
null
end col1,
b.col2 col2,
b.col3 col3
from
(
select distinct col1,col2,col3, rownum() over(partition by col1) c_1 from table_name
)b
now assume / modify above query -
table_name is the table name
col1 , col2 and col3 is your table's column name.
just modify this query as per your table name and structure and see..
it would be your required solution.
I know that this is an old question but thought this might be of use to other people. After researching this for awhile, there is a keyword called DISTINCT that will show duplicate values in a query only once. I was using a query to auto-suggest values in a text box on a web page and didn't want it to show duplicate names and this worked for me:
SELECT DISTINCT FIRSTNAME
FROM TBLSTUDENTS
WHERE FIRSTNAME LIKE '#ucase(arguments.search)#%'

Tricky SQL statement over 3 tables

I have 3 different transaction tables, which look very similar, but have slight differences. This comes from the fact that there are 3 different transaction types; depending on the transaction types the columns change, so to get them in 3NF I need to have them in separate tables (right?).
As an example:
t1:
date,user,amount
t2:
date,user,who,amount
t3:
date,user,what,amount
Now I need a query who is going to get me all transactions in each table for the same user, something like
select * from t1,t2,t3 where user='me';
(which of course doesn't work).
I am studying JOIN statements but haven't got around the right way to do this. Thanks.
EDIT: Actually I need then all of the columns from every table, not just the ones who are the same.
EDIT #2: Yeah,having transaction_type doesn't break 3NF, of course - so maybe my design is utterly wrong. Here is what really happens (it's an alternative currency system):
- Transactions are between users, like mutual credit. So units get swapped between users.
- Inventarizations are physical stuff brought into the system; a user gets units for this.
- Consumations are physical stuff consumed; a user has to pay units for this.
|--------------------------------------------------------------------------|
| type | transactions | inventarizations | consumations |
|--------------------------------------------------------------------------|
| columns | date | date | date |
| | creditor(FK user) | creditor(FK user) | |
| | debitor(FK user) | | debitor(FK user) |
| | service(FK service)| | |
| | | asset(FK asset) | asset(FK asset) |
| | amount | amount | amount |
| | | | price |
|--------------------------------------------------------------------------|
(Note that 'amount' is in different units;these are the entries and calculations are made on those amounts. Outside the scope to explain why, but these are the fields). So the question changes to "Can/should this be in one table or be multiple tables (as I have it for now)?"
I need the previously described SQL statement to display running balances.
(Should this now become a new question altogether or is that OK to EDIT?).
EDIT #3: As EDIT #2 actually transforms this to a new question, I also decided to post a new question. (I hope this is ok?).
You can supply defaults as constants in the select statements for columns where you have no data;
so
SELECT Date, User, Amount, 'NotApplicable' as Who, 'NotApplicable' as What from t1 where user = 'me'
UNION
SELECT Date, User, Amount, Who, 'NotApplicable' from t2 where user = 'me'
UNION
SELECT Date, User, Amount, 'NotApplicable', What from t3 where user = 'me'
which assumes that Who And What are string type columns. You could use Null as well, but some kind of placeholder is needed.
I think that placing your additional information in a separate table and keeping all transactions in a single table will work better for you though, unless there is some other detail I've missed.
I think the meat of your question is here:
depending on the transaction types the columns change, so to get them in 3NF I need to have them in separate tables (right?).
I'm no 3NF expert, but I would approach your schema a little differently (which might clear up your SQL a bit).
It looks like your data elements are as such: date, user, amount, who, and what. With that in mind, a more normalized schema might look something like this:
User
----
id, user info (username, etc)
Who
---
id, who info
What
----
id, what info
Transaction
-----------
id, date, amount, user_id, who_id, what_id
Your foreign key constraint verbiage will vary based on database implementation, but this is a little clearer (and extendable).
You should consider STI "architecture" (single table inheritance). I.e. put all different columns into one table, and put them all under one index.
In addition you may want to add indexes to other columns you're making selection.
What is the result schema going to look like? - If you only want the minimal columns that are in all 3 tables, then it's easy, you would just UNION the results:
SELECT Date, User, Amount from t1 where user = 'me'
UNION
SELECT Date, User, Amount from t2 where user = 'me'
UNION
SELECT Date, User, Amount from t3 where user = 'me'
Or you could 'SubClass' them
Create Table Transaction
(
TransactionId Integer Primary Key Not Null,
TransactionDateTime dateTime Not Null,
TransactionType Integer Not Null,
-- Othe columns all transactions Share
)
Create Table Type1Transactions
{
TransactionId Integer PrimaryKey Not Null,
// Type 1 specific columns
}
ALTER TABLE Type1Transactions WITH CHECK ADD CONSTRAINT
[FK_Type1Transaction_Transaction] FOREIGN KEY([TransactionId])
REFERENCES [Transaction] ([TransactionId])
Repeat for other types of transactions...
What about simply leaving the unnecessary columns null and adding a TransactionType column? This would result in a simple SELECT statement.
select *
from (
select user from t1
union
select user from t2
union
select user from t3
) u
left outer join t1 on u.user=t1.user
left outer join t2 on u.user=t2.user
left outer join t3 on u.user=t3.user