I'm testing SymmetricDS and I'm having some doubt about which approach I should use to synchronize some specific tables. I have two application, the first is a ERP and the second is a PDV. Some tables can be synchronized to all PDV databases, however, in some tables the row should synchronize to a specific PDV instance:
In this diagram, the red rectangles show which table need synchronize, and the green arrow show the column where we can identify which SymmetricDS instance will synchronize. My question is: which approach I should use to do this (bsh, subselect, lookuptable, etc) and how I do it?
You need a subselect router (actually you need three). I only show you the SQL for Funcionario, then you'll be able to figure out the configuration for Cadastro and Funcionario_funcao by yourself:
insert into SYM_ROUTER
(router_id, source_node_group_id, target_node_group_id, router_type,
router_expression, create_time, last_update_time)
values
('erp_to_pdv__funcionario', 'erp', 'pdv', 'subselect',
'c.external_id in (
select empresa.CNPJ
from cadastro join empresa
on cadastro.id_empresa = empresa.id_empresa
where cadastro.CPFCGC=:ID_CADASTRO
)',
current_timestamp, current_timestamp);
When a record from the Funcionario table is routed, this router picks all the nodes with external_id equal to the Empresa.CNPJ linked to the given Funcionario (I assumed Funcionario.id_cadastro to be the reference to Cadastro.CPFCGC)
Note I used c.external_id, but you may want to use c.node_id (depends on what you put into Empresa.CNPJ).
Related
I'm looking to have a GUI where when I click an Invoice it displays the information from both Customer and Product also, such as name, brand etc all in one row.
Do I have to put Name, brand, etc into Invoice too and inner join everything?
Invoice Table Customer Table Product Table
EDIT:
No, no need to modify the tables you're referring to. They all contain a unique primary key column which are referenced from the invoice table. Based on them the INNER JOIN can be formulated.
Maybe also worth mentioning: Don't confuse the INNER JOIN with the SELF JOIN which also exists.
The difference is that the INNER JOIN is still joining two different tables based on specific columns (e.g. id) whereby the SELF JOIN is joining a single table with itself.
Yes what you'll need is the INNER JOIN combining the information from your invoice table with the one from the customer table as well as the product table - all based on your given invoice id (column: idInvoice).
To obtain the needed information you don't need to add - and therefore repeat - it in the invoice table. Due to the join they'll be available for selection in one single query.
Your query should look like:
SELECT *
FROM invoice inv, customer cust, product prod
WHERE
inv.idCustomer = cust.idCostumer
AND
inv.idProduct = prod.idProduct
AND
inv.idInvoice = ${theIdOfTheInvoiceTheUserClickedOn}
Note: If you don't need all the information (columns) from the three tables (what the "*" stands for) you can replace the "*" with an enumeration explicitly stating only the columns you want to show. E.g. inv.id, cust.FirstName, cust.LastName.
Depending on the database technology/ dialect you're exactly using. The example above would be suitable for an Oracle database and should also suite most other databases, since only basic SQL features are being used in the query.
I'm assuming you're not using any ORM framework like Hibernate and that you'll need to write the query yourself (since you didn't provide any more detail on your technology stack). In case youre using an ORM framework the approach would need to look different, but the final generated query should look similar.
In the query above the first two conditions in the WHERE clause are forming the INNER JOIN implicitly, whereby the last third one is specifying which exact entry you're looking for.
Although you've asked only if an INNER JOIN is needed, I've provided the query here to you since your question implied you're not sure how to write one.
You might take it as an working example you can compare your solution with. You should try to understand how it's working and how it can be written and also research more on the SQL basics so that you can write it on your own as well.
Tip: PreparedStatements are the way to go to execute such queries to a database from Java in a safe way
In my opinion, based on your application, you can use a flat table that includes what you need and doesn't need to join tables. This solution is applicable when you are in a situation that you have small datasets (E.g. in banking, relationships between Terminal table and ATMTerminal, POSTerminal and CashlessTerminal tables).
And for situations that you have a relationship that one side is static data (like the above example) and another side is transactional data (like Banking Transactions), you should use the foreign key from the transaction table to the static data table.
I recommend you to use the second solution for your problem and handle relationships using foreign keys and get the columns you need using the join strategy.
I need something which I dont know if it's possible to achieve. Basically I'll be adding new rows of information from java to a database with the table structure , ex:
Number | Color | Size
0 | Red | Big
1 | Green | Small
2 | Yellow| Medium
I'm using java and I'll only input the Color and Size, and I would like to know if it's possible to create a trigger that will store the variable Number(id) on the database side, and increment it each time I do an Insert of a new row into the db. I was thinking doing something like, " INSERT INTO table ((null),'Red', 'Big'), and then the database would update the value with the proper Number.
Also should be possible to bare with fact that some rows can be deleted, but it won'shouldn't affect anything, example: if I have ID's 0 , 1 ,2 and I delete 1, next row should still be 3.
Another thing, I'm using Sybase SQL Anywhere 12 to do this.
You should use autoincrement column in your database.
See this.
http://www.sqlines.com/sybase-asa/autoincrement_identity
As #Gordon Linoff said ...
Identity columns are doing that, for example ...
create table T1 (ID int identity(1,1), Name nvarchar(100))
In this case you would go ...
insert into T1 (Name) values ('John')
So, you would insert Name 'John' and DB itself would give him ID 1
Next time you do insert, ID 2 would be set ... and so on and on ..
Identity(1,1) - it means start from 1 and increment it by 1 on new insert
Thing about this is that once number is taken, there is no going back, so if you have IDs 1, 2, 3 .. and delete ID 3 .. on next insert ID will go up to 4, it will not populate "missing number"
there are several solutions that satisfy your requirements but those are different in several aspects and you should decide to select the best one.
some solutions are exists in DB context. (for example #Gregory answer),
but some other solutions are independent of the DB type and specific features. it means that you implement your solution independent of your db type and you could change your db (oracle, sql-server, my-sql , ...) and there is no need to change your java code.
in jpa there are three Sequence Strategies to solving this problem with #GeneratedValue.
1) Table sequencing: you use a separate table for this purpose in your db. this table hold the proper ids for other tables that have auto-increment-columns with this strategy.
2) Sequence objects: you use a sequence object in your db and jpa handle it. Sequence objects are only supported in some databases, such as Oracle, DB2, and Postgres.
3) Identity sequencing: uses special IDENTITY columns in the database to allow the database to automatically assign an id to the object when its row is inserted. Identity columns are supported in many databases, such as MySQL, DB2, SQL Server, Sybase, and PostgreSQL. Oracle does not support IDENTITY columns but it is possible to simulate them using sequence objects and triggers.
if you want to be independent from your db type, I recommend you to use "table strategy" in jpa.
see Java Persistence/Identity and Sequencing for details.
you asked:
I would like to know if it's possible to create a trigger that will
store the variable Number(id) on the database side, and increment it
each time I do an Insert of a new row into the db.
yes, you could use trigger, but as i mentioned there are some simpler solutions rather it.
Also should be possible to bare with fact that some rows can be
deleted, but it won'shouldn't affect anything
in jpa solutions the deleted ids don't be used in next usage, but if you implement your own solution you could use them.
I hope this answer help you.
I'm relatively new to working with JDBC and SQL. I have two tables, CustomerDetails and Cakes. I want to create a third table, called Transactions, which uses the 'Names' column from CustomerDetails, 'Description' column from Cakes, as well as two new columns of 'Cost' and 'Price'. I'm aware this is achievable through the use of relational databases, but I'm not exactly sure about how to go about it. One website I saw said this can be done using ResultSet, and another said using the metadata of the column. However, I have no idea how to go about either.
What you're probably looking to do is to create a 'SQL View' (to simplify - a virtual table), see this documentation
CREATE VIEW view_transactions AS
SELECT Name from customerdetails, Description from cakes... etc.
FROM customerdetails;
Or something along those lines
That way you can then query the View view_transactions for example as if it was a proper table.
Also why have you tagged this as mysql when you are using sqlite.
You should create the new table manually, i.e. outside of your program. Use the commandline 'client' sqlite3 for example.
If you need to, you can use the command .schema CustomerDetails in that tool to show the DDL ("metadata" if you want) of the table.
Then you can write your new CREATE TABLE Transactions (...) defining your new columns, plus those from the old tables as they're shown by the .schema command before.
Note that the .schema is only used here to show you the exact column definitions of the existing tables, so you can create matching columns in your new table. If you already know the present column definitions, because you created those tables yourself, you can of course skip that step.
Also note that SELECT Name from CUSTOMERDETAILS will always return the data from that table, but never the structure, i.e. the column definition. That data is useless when trying to derive a column definition from it.
If you really want/have to access the DB's metadata programatically, the documented way is to do so by querying the sqlite_master system table. See also SQLite Schema Information Metadata for example.
You should read up on the concept of data modelling and how relational databases can help you with it, then your transaction table might look just like this:
CREATE TABLE transactions (
id int not null primary key
, customer_id int not null references customerdetails( id )
, cake_id int not null references cakes( id )
, price numeric( 8, 2 ) not null
, quantity int not null
);
This way, you can ensure, that for each transaction (which is in this case would be just a single position of an invoice), the cake and customer exist.
And I agree with #hanno-binder, that it's not the best idea to create all this in plain JDBC.
Hi I have a case where I need to do this select statement
SELECT c.*, count(r.competitorid) as num_comp, num_event.num_events
from competition c left join regcomp r on c.competitionid = r.competitionid
left join
(
select competition.competitionid, count(e.competitionid) as num_events
from competition left join `event` e on competition.competitionid = e.competitionid
group by competition.competitionid
) as num_event on c.competitionid = num_event.competitionid
)
AS winners ON winners.competitionid = c.competitionid;
My problem is that I do not know what pattern follow, or if there's a set of methods that I need to call to create the datasource for this table. I can create an IndexedContainer and add container properties, then add that to the Vaadin table, which is what I'm doing - but the problem is when I try to persist data, I am not able to use JPA later if I don't use it at the start.
JPA lets you access referenced tables via foreign keys very conveniently by doing setVisibleColumns("parent.child") and so it is possible in theory to show any information about a single row by picking the correct entry-entity so to speak.
But what do I do if I want to create a table that shows counts in one of the columns, obviously the count is not part of the entity - but if it isn't part of the entity how can I use the benefits of JPA on tables that include data generated by stuff like avg(), count() etc.
P.S. the query retrieves a table showing all the competitions and how many competitors and events are in that competition.
This depends on what JPA provider you use.
When using Hibernate you can use calculated properties as mentioned in this post.
It then gives such annotations:
#Formula("PRICE*1.155")
private float finalPrice;
or even more complex
#Formula("(select min(o.creation_date) from Orders o where o.customer_id = id)")
private Date firstOrderDate;
Look at the other post for more details on this Hibernate feature.
For EclipseLink/Toplink I know of no solution to the problem
Persistence means you have strong link between your classes and database tables, which are "hard, durable" things.
In your queston you are fetching data from a query, not a table, so talking about persistence in this context is not correct.
What you can do is to add in your Table a custom column where you make your custom things,
or make a database view and create an Entity on it (could autogenerate with JPATools) if you want to have the full power of JPAContainer.
Cheers.
For a customer we where developing a big application that where open to all users if you will, meaning, all users could see each others data.
Now suddenly the customer is saying that they want only users belonging to the same organization to be able to view each others data.
So we came up with this data model:
So now the question is: How is it best to separate the data?
This is the only alternative I see:
SQL JOIN on ALL relevant tables (All tables that have data should no always join on Organization)
-- All queries should now add an extra join to Organization, and if the join doesn't exists, we need to create a new foreign key.
But I feel an extra join (We have around 20 tables that needs extra join) is quite costly.
I hope there are some other best practices or solutions we can consider.
PS: This is a Web application developed using Java/JSF/Seam (but I don't know if that is relevant)
UPDATE
I want to clarify something. My consurn is not security but performance. We have added the foreign key to organization to all relevant tables that has shared data, and we are using user's logged in organization to filter the data.
All I want to know is if this is a good architectural solution (inner join) or if we should do something else (ie: Load all shared data, and filter in memory instead of sql join).
You really have to understand the difference between the persistency layer and the application layer.
It doesn't matter how you define your database tables, as anyone with database access will have access to all the users data. What does matter is how you define the behavior in your application.
Changing the database design should only be done for performance reasons, not for security - which should be handled in the application.
I would reckon that the best pattern would be to only expose the user details through the web application, so at that point its a case of restricting the data exposed to each user. This will allow you to build in the required security inside the application.
Alternatively if you are allowing direct database access then you will need to create a login/user (depends on database used) for each organization or user and then restrict the access of these login/user entities to parameterized stored procedures rather than the base tables. This will push security back onto the database, which is riskier but still do-able.
As to meta changes to support the organization column, parameterizing the stored procedures will be fairly trivial:
select #organizationId = organizationId from User where User.id = #currentUserId
select * from User where organizationId = #organizationId
(depending on the sql flavour you will need to enclose some entities eg ``User, [User] etc)
I see no reason that Organization has to be 'joined' at all.
If your 'data' tables all have OrganizationID columns, then you can lookup the 'organizationID' from the user and then add this as a condition to the join.
EX:
select #OrganizationId = organizationId from User where User.id = #currentUserId
select * from datatable a .... where .... AND a.organizationID = #organizationID
See; no join.
With respect to performance, there are different types of joins, and SQLServer allows you to hint at the type of join. So in some cases, a merge join is the best, whereas in something like this scenario, a loop join would be the best. Not sure if these choices are available in MySQL.
With respect to all of your tables needing a join, or condition (see above), there is a logical answer, and an implementation answer. The implementation answer depends on your indexing. If you can limit the dataset the most by adding that condition, then you will benefit. But if the join with the other table that has already been filtered does a better job at reducing rows, then the condition will be worthless (or worst case, it will use the wrong index). Assuming you have indexes on your join and condition columns.
Logically, only data that isn't fully dependent on a table that is filtered by organizationID needs that extra condition. If you have a car table, and carparts table, then you only have to filter the car table. Unless for some reason you don't need to join with the car table for some joins, in which case you will need that organizationID on the parts table too.