so I have this problem: I have 3 different tables that need to be connected to one another. It's rather complex and my english skills aren't that good. Let me show you:
T1 T2 T3
ID_T1 |Name | |ID_T1|ID_T2| |ID_T2|Spent|
1 |James| | 1| 4| | 4 | 200 |
2 |Mike | | 2| 5| | 5 | 300 |
3 |Alex | | 3| 6| | 6 | 400 |
Basically I want to connect in Table T3 the amount spent with the names in T1 by using the ID I have in T2.
So I should "read" that James spent 200 dollars, Mike spent 300 and Alex 400.
Another thing to know is that the IDs are generated automatically, so I'm not supposed to be able to see them.
Do I have to pay attention on something when I create my Tables, or do I have to focus more on the INSERT INTO command (I work with Oracle sql Developer)?
Thank you very much! :)
#Burkinaboy might wanna try this
SELECT
T1.Name,
T3.SPent
FROM T1 t0 RIGHT JOIN T2 t1 ON T1.ID_T1 = T2.ID_T1 RIGHT JOIN T3 t2 ON T3.ID_T2=T2.ID_T2
This should give you an expected output.
Select a.Name, c.spend
From T1 a, T2 b, T3 c
Where a.Id_T1 = b.Id_T1
AND b.Id_T2 = c.Id_T2
Regarding your second question, you should know the relation between the tables meaning how they are connected.
Updating the answer as per your comments . Assuming that amount spend column you are going to hard code..
Select b.Id_T2 , "300"
From T1 a ,T2 b
Where a.Id_T1 = b.Id_T1
But in above case , all the values for column spend would be 300.
SELECT T1.name, T3.spent FROM T1, T3 WHERE T1.ID_T1=T2.ID_T1 AND T2.ID_T2=T3.ID_T2
select t1.name as name, t3.spent as spent
from t1
join t2 on t2.id_t1 = t1.id_t1
join t3 on t3.id_t2 = t2.id_t2
Use join instead of putting all tables in FROM clause.
Assuming you are inserting every spending in T3 table with a new ID, you can join the three tables and do a group by on it:
select
T1.ID_T1 ID,
T1.NAME,
SUM(T3.SPENT) SPENT
from T1 inner join T2 on T1.ID_T1 = T2.ID_T1
inner join T3 on T2.ID_T2 = T3.ID_T2
GROUP BY T1.ID_T1, T1.NAME;
As of now, It's not clear which database you're using exactly. (I assumed that it's Oracle as you're using Oracle SQL Developer. Similar solution should be available in other DBMS as well in case it's not.).
First, Let's create the tables:
create table t1 (
ID_T1 integer primary key,
Name varchar2(100)
);
create table t2 (
ID_T1 integer,
ID_T2 integer,
constraint pk primary key(ID_T1,ID_T2)
);
create table t3 (
ID_T2 integer primary key,
spent number(10,2)
);
Then create two sequences that'll be used while inserting:
create sequence t1_seq start with 1 increment by 1;
create sequence t2_seq start with 1 increment by 1;
Then a view which will display spendings per person:
create or replace view spendings
as
select
T1.ID_T1 ID,
T1.NAME,
SUM(T3.SPENT) SPENT
from T1 inner join T2 on T1.ID_T1 = T2.ID_T1
inner join T3 on T2.ID_T2 = T3.ID_T2
GROUP BY T1.ID_T1, T1.NAME;
Then create an INSTEAD OF trigger on the above view to make the proper inserts in underlying tables:
create or replace trigger spendings_trig
instead of INSERT or UPDATE or DELETE on SPENDINGS
for each row
declare
v_ID_T1 integer;
v_ID_T2 integer;
v_name t1.name%type;
begin
if not inserting then
raise_application_error(-20001,'Not supported');
end if;
begin
if :new.ID is null then
v_ID_T1 := T1_SEQ.NEXTVAL;
insert into T1 (ID_T1, NAME) values (v_ID_T1, :new.NAME);
end if;
select ID_T1,NAME into v_ID_T1,v_name from T1
where ID_T1 = :new.ID;
if :new.name is not null and v_name <> :new.name then
raise_application_error(-20002,'Incorrect name entered');
end if;
exception
when no_data_found then
v_ID_T1 := :new.ID;
insert into T1 (ID_T1, NAME) values (v_ID_T1, :new.NAME);
end;
v_ID_T2 := T2_SEQ.NEXTVAL;
insert into T2 values (v_ID_T1, v_ID_T2);
insert into T3 values (v_ID_T2, :new.spent);
end;
/
Now if you insert into the view like this (assuming there is no data in any of the tables):
insert into spendings (name, spent) values ('James',100);
T1 will get a row
ID_T1 NAME
------------
1 James
T2 will get a row
ID_T1 ID_T2
------------
1 1
T3 will get a row
ID_T2 SPENT
-------------
1 100
Now if you do:
insert into spendings (id,spent) values (1,100);
T1 will not be inserted as there is already row present for ID = 1
T2 will get a row:
ID_T1 ID_T2
------------
1 1
1 2
T3 will get a row
ID_T2 SPENT
-------------
1 100
2 100
And
select * from spendings;
will show:
ID NAME SPENT
------------------
1 James 200
Related
I have a table 1 as below (Simplified versions show here as the actual one has over 60+ columns)
ID
Description
From_Index_Code
To_Index_Code
Cost
PARAM1
PARAM2
A
Something.
A001
B001
500
abc.
xyz.
B
Something2.
B001.
C001
1000
abc.
xyz.
I have a master table that is of the following structure:
ID
Code.
Value
1
A001.
100.
2
B001.
200.
3
C001.
300.
Now I have an input that has the following values:
PARAM1=abc,PARAM2=xyz and Index value as 150. I need to check if the index value is between A001 and B001, if yes, return 500. If it is between B001 and C001 then I return 1000.
I tried doing
WITH
src_1 as (select id,s.description,g.value
from table1 s left outer join table 2 g on s.from_index_code=g.code),
src_2 as (select id,s.description,g.value
from table1 s left outer join table 2 g on s.to_index_code=g.code)
select src_1.id, src_1.description,src_1.value as 'from_value',src_2.value as 'to_value' from src_1 ,src_2 where src_1.id=src_2.id.
I expect the resulting set to be something like:
ID
Description
From_Value
To_Value
A
Something.
100.
200.
B
Somethng2.
200.
300.
It should have the same number of rows as Table 1. But the resulting output has far too many rows.
Table 1 has 8497 rows.Table 2 has 121 rows. However the resulting output has over 14 million rows.
What is the best way to accomplish this?
Any help would be much appreciated.
Thanks.
your problem was, that you select id in the subselect and so mysql chooses wrong, adding a s to the ids columns clears everything up and gets the correct result
CREATE TABLE table1
(`id` varchar(1), `Description` varchar(11), `From_Index_Code` varchar(5), `To_Index_Code` varchar(4), `Cost` int, `PARAM1` varchar(4), `PARAM2` varchar(4))
;
INSERT INTO table1
(`id`, `Description`, `From_Index_Code`, `To_Index_Code`, `Cost`, `PARAM1`, `PARAM2`)
VALUES
('A', 'Something.', 'A001', 'B001', 500, 'abc.', 'xyz.'),
('B', 'Something2.', 'B001.', 'C001', 1000, 'abc.', 'xyz.')
;
CREATE TABLE table2
(`id` int, `Code` varchar(4), `Value` int)
;
INSERT INTO table2
(`id`, `Code`, `Value`)
VALUES
(1, 'A001', 100.),
(2, 'B001', 200.),
(3, 'C001', 300.)
;
WITH
src_1 as (select s.id,s.description,g.value
from table1 s left outer join table2 g on s.from_index_code=g.code),
src_2 as (select s.id,s.description,g.value
from table1 s left outer join table2 g on s.to_index_code=g.code)
select src_1.id, src_1.description,src_1.value as 'from_value',src_2.value as 'to_value' from src_1 ,src_2 where src_1.id=src_2.id
id | description | from_value | to_value
:- | :---------- | ---------: | -------:
A | Something. | 100 | 200
B | Something2. | null | 300
db<>fiddle here
Hmmm . . . I am thinking you want joins and conditions like this:
select t1.*
from table1 t1 join
table2 t2f
on t2f.code = t1.From_Index_Code join
table2 t2t
on t2t.code = t1.to_index_code
where t1.param1 = #param1 and t2.param2 = #param2 and
#index_value between t2f.value and t2t.value;
For performance, you would want indexes on table1(param1, param2, from_index_code, to_index_code) and on table2(code) (if it is not already the primary key).
I am trying to select the ids of 3 columns that I have in my table that all contain the same data except for when the first occurrence of the duplicate was inserted. For example my table is as follows:
Select * From Workers
+----+--------+--------+--------------+
| id | name |JobTitle| description |
+----+--------+--------+--------------+
| 1 | john |Plumber |Installs Pipes|
| 2 | mike | Doctor |Provides Meds |
| 3 | john |Plumber |Installs Pipes|
| 4 | john |Plumber |Installs Pipes|
| 5 | mike | Doctor |Provides Meds |
| 6 | mike | Doctor |Provides Meds |
+----+--------+--------+--------------+
What im basically trying to get is the ids of all the duplicates records expect for the lowest or first id where a duplicate has occurred.
SELECT t1.id
From workers t1, workers t2
Where t1.id > t2.Id and t1.name = t2.name and t1.jobTitle = t2.jobTitle and t1.description = t2.description;
The table i am working with had hundred of thousands of records and I have tried the statement above to get the ids i want but due to the size of the table I get the error:
Error Code: 1054. Unknown column 't1.userId' in 'where clause'
I have tried increasing the timeout in workbench but to no avail.
In this example I am basically trying to get all the ids except for 1 and 2. I thought the above query would have got me what i was looking for but this has not been the case and now I am not sure what else to try.
Any help is greatly appreciated. Thanks in advance.
You can do it with an 'INNER JOIN
SELECT DISTINCT t1.*
From workers t1
INNER JOIN workers t2 ON t1.name = t2.name and t1.jobTitle = t2.jobTitle and t1.description = t2.description
Where t1.id > t2.Id ;
But i can't figure out how you got your message, there is no userid in sight
The error message does not match your query (there is no userId column in the query) - and it is not related to the size of the table.
Regardless, I would filter with exists:
select w.*
from workers w
where exists (
select 1
from workers w1
where
w1.name = w.name
and w1.jobTitle = w.jobTitle
and w1.description = w.description
and w1.id < w.id
)
For performance, consider an index on (name, jobTitle, description, id).
I have one table that contains the prefix of Job Numbers. The other table contains the complete Job number as well as several of other columns of data. I would like to return the below result using sql.
Table 1
PfxJobNum
--------
001
006
024
Table 2
Id JobNum
--------
1 001aed
2 001bef
3 924bac
4 006aab
5 056bcb
6 084baa
Result
Id JobNum
--------
1 001aed
2 001bef
4 006aab
You can try to use a subquery with exists .... like
SELECT *
FROM Table2 t1
WHERE exists (
select 1
FROM Table1 t2
WHERE t1.JobNum like t2.PfxJobNum +'%'
)
sqlfiddle
or use CONCAT
Schema (MySQL v5.7)
create table Table1(
PfxJobNum varchar(50)
);
INSERT INTO Table1 VALUES ('001');
INSERT INTO Table1 VALUES ('006');
INSERT INTO Table1 VALUES ('024');
create table Table2(
Id INT,
JobNum varchar(50)
);
INSERT INTO Table2 VALUES (1,'001aed');
INSERT INTO Table2 VALUES (2,'001bef');
INSERT INTO Table2 VALUES (3,'924bac');
INSERT INTO Table2 VALUES (4,'006aab');
INSERT INTO Table2 VALUES (5,'056bcb');
Query #1
SELECT *
FROM Table2 t1
WHERE exists (
select 1
FROM Table1 t2
WHERE t1.JobNum like CONCAT(t2.PfxJobNum ,'%')
);
| Id | JobNum |
| --- | ------ |
| 1 | 001aed |
| 2 | 001bef |
| 4 | 006aab |
View on DB Fiddle
If your prefix is always the same length, I would advise:
select t2.*
from table2 t2
where exists (select 1
from table1 t1
where t1.PfxJobNum = left(t2.JobNum, 3)
);
This is the preferred method, because it can take advantage of an index on table1(PfxJobNum).
Not all databases support left(); in such cases, substr() or substring() works fine.
If the prefixes can vary in length, then use like:
select t2.*
from table2 t2
where exists (select 1
from table1 t1
where t2.JobNum like t1.PfxJobNum || '%'
);
Not all databases use the standard || for string concatenation. In those databases, use the appropriate operator.
I was able to get this to work in MS Access and in MySQL 5.7. What is the difference between this and WHERE EXISTS(... ?
SELECT *
FROM Table1, Table2
WHERE Left(Table2.JobNum,3)=Table1.PfxJobNum;
I have an issue where a mistake resulted in a database table having both emails and GUIDs mixed in the ID column.
The table looks like this (simplified):
GUID | Value | Date
cf#a | 21 | 2016
mf#b | 42 | 2015
mf#b | 21 | 2016
1aXd | 3 | 2016
a7vf | 9 | 2015
Where for example user cf#a and user 1aXd are the same. The GUID - Email combinations are stored in another table. The emails are unique. Primary key is the ID(GUID) and the Date combined. My problem is, how do i update the table and merge the rows? the Value column of two merging rows should be summed.
So the example table assuming (cf#a -> 1aXd and mf#b -> 8bga and ui#q -> a7vf) would become:
GUID | Value | Date
1aXd | 24 | 2016 <-- merged, Value = 21+3
8bga | 42 | 2015 <-- converted to GUID
8bga | 21 | 2016 <-- converted to GUID
<-- one row removed (merged with the first one)
a7vf | 9 | 2015 <-- untouched
Thank you for any help!
I could do this in C# but i would rather learn how to do it with the MySQL Workbench
Use JOIN:
SELECT t1.Value + t2.Value
FROM t1
JOIN t2 USING (`GUID`)
If you want update values, you need something like this:
UPDATE t1
JOIN t2 USING (`GUID`)
SET t1.Value = t1.Value + t2.Value
Removing merged rows:
DELETE t2 FROM t2
JOIN t1 USING (`GUID`)
UPDATE
If has only one table.
Merge:
UPDATE t1
JOIN (
SELECT GUID, SUM(Value) as amount, COUNT(1) as cnt
FROM t1
GROUP BY `GUID`
HAVING cnt > 1
) t2 ON t2.GUID = t1.GUID
SET t1.Value = t2.amount;
Delete:
CREATE table t2 (
GUID integer,
Value integer,
Date integer
);
INSERT INTO t2 (GUID, Value, Date)
SELECT GUID, Value, MAX(Date) FROM t1 GUID, Value;
Result will be in t2.
I have two rows each of which contain a week a day and an event. An auto increment primary key is used to distinguish the rows.
Here is an example:
ID Week Day event
-------------------------------
1 | 1 | 2 | house keeping
2 | 2 | 3 | house viewing
What i want to do is swap the week and day of the two rows specified so that it looks like this:
ID Week Day event
-------------------------------
1 | 2 | 3 | house keeping
2 | 1 | 2 | house viewing
But the Id must remain the same
Ive been reading through other peoples posts and found this solution which uses temporary variables to swap only one columns values from each row.
UPDATE my_table SET a=#tmp:=a, a=b, b=#tmp;
Could anyone help me swap two columns instead of just the one?
thanks
I assume you have just 2 rows in your table.
If not, you need to modify slightly the JOIN conditions.
Here is one possible approach.
CREATE TEMPORARY TABLE T(ID int, Week int, Day int)
INSERT INTO T(ID, Week, Day)
SELECT ID, Week, Day from TableName;
UPDATE TableName t1
JOIN T t2 on t1.ID <> t2.ID
SET
t1.Week = t2.Week,
t1.Day = t2.Day;
DROP TEMPORARY TABLE T;
And here is a better one.
UPDATE
tablename AS t1
JOIN tablename AS t2 ON
( t1.id <> t2.id )
SET
t1.week = t2.week,
t2.week = t1.week,
t1.day = t2.day,
t2.day = t1.day;