-1

I am using delphi and I would like to join 2 or more datasets dynamically in one larger . I am going to show the result of the merge in a dbgrid .

What would be the best solution ?

Thank you in advance

  • 2
    "Best" is a matter of opinion, which is off-topic here. What database type are you using? Also which Delphi version and which Delphi db components? – MartynA Jan 27 '17 at 16:28
  • Hi thanks for the reply. – Johny Arduino Jan 27 '17 at 16:29
  • I am using xe7 saving the data to a microsoft sql server 2008. I am using Ado components. – Johny Arduino Jan 27 '17 at 16:30
  • What do you mean by "join"? why won't you query the server to join the data and return it to a single dataset? please [edit](http://stackoverflow.com/posts/41898563/edit) your question and be more specific. – kobik Jan 27 '17 at 16:37
  • I think OP has two TDataSet objects somewhere and wants to return a single new TDataSet with the records of both of them – Agustin Ortu Jan 28 '17 at 03:32
  • Yes exactly this what I want to do :) – Johny Arduino Jan 28 '17 at 07:33
  • Yes I have 2 tables with the same columns but they are in different servers .I have tried the linked servers in sql and it works fine .But I want to find a solution without using linked servers . Getting the data from the tables and putting the data on a single TDataset to show this in a single TDBGrid – Johny Arduino Jan 28 '17 at 07:41

2 Answers2

2

Using Sql Server you can construct a SQL query in its TransactSQL which uses the JOIN construct to "connect" two tables together. See for example this previous answer:SQL Server: Multiple table joins with a WHERE clause.

You should take a look at the TransactSQL documentation on MSDN, e.g.

https://msdn.microsoft.com/en-us/library/zt8wzxy4.aspx.

The following is an example to retrieve authors and their titles from the demo Pubs database for Sql Server:

use pubs
select
  a.au_id, 
  a.au_fname,
  a.au_lname,
  t.title
from
  authors a
  join titleauthor x on a.au_id = x.au_id
  join titles t on x.title_id = t.title_id
order by
  a.au_lname, a.au_fname

You can execute it to try it out in SqlServer Management Studio by using New Query, then try pasting it into a TAdoQuery in a Delphi project.

A good way to visualise the result of a JOIN is to use a TBGrid. However, a JOIN is not always a good thing to use if you are wanting to edit the contents of one or more of its tables. For example, a business task might be to edit details of an author's books. To do that, a more convenient was than a JOIN might be to connect the Authors and Titles tables in your app, using AdoQuerys, by setting up a so-called Master-Detail relationship between them. There are various ways to do that and maybe you best bet would be to google a Delphi tutorial about how to set up and use them.

In SQL, the UNION construct is another way of getting data from two separate tables.

Btw Ado components, e.g. TAdoQuery, will work fine for what you want to do. If you have a version of Delphi, you could try that, too, but it's maybe a bit more daunting if you've no done this type of thing before.

Update You've said in comments that you want to get data from two servers to end up in one dataset without using Sql Server's "linked servers" method.

To do this is quite straightforward: it takes a bit of setting up but the merging of the data can be done in two lines of code. Here's how:

  1. For each server, place the following on your form/datamodule: An AdoConnection, AdoQuery, DataSetProvider and ClientDataSet. Configure the AdoConnection to connect to one of the servers, set the AdoQuery to use the AdoConnection, and set the DataSet property of the DataSetProvider to the AdoQuery. Set the ProviderName property of the ClientDataSet to the DataSetProvider. Add a DataSource and set its DataSet property to the ClientDataSet and a DBGrid connected to the DataSource. Give these component's names A and B suffixes.

Using the Pubs database example, set the AdoQuery's SQL.Text property to

  select
    [Source] = 'ServerA',  -- and ServerB for the other one of course
    *
  from
    authors
  1. Check that both sets of components are working by setting the two CDS's Active property to True. In the Form's FormCreate event, add code to open both CDSs.

  2. Add a third ClientDataSet, 'cdsMergedData' to the form and give it its own DataSource and DBGrid. Set cdsMergedData's IndexFieldNames to 'au_lname;au_fname'.

  3. Put a TButton 'btnMerge' on the form and add the following code to its OnClick event :

    cdsMergedData.Data := cdsServerA.Data;

    cdsMergedData.AppendData(cdsServerB.Data, True);

and that's it. The True argument to AppendData tells cdsMergedData that there is no more data to load. If you wanted to add data from a third server, you would set it to False for cdsServerB and True for cdsServerC.

There is no code-free way of feeding data changes made in cdsMergedData back to the source server. You would need to copy the changes to the counterpart row in the relevant cdsServer CDS, and then call ApplyUpdates on it.

Community
  • 1
  • 1
MartynA
  • 30,454
  • 4
  • 32
  • 73
  • Hi! I have tried the solution with Union in sql using linked servers and doing queries with Adoquery . But I would like to do it without using linked servers . To get data from tables that are in different sql servers . For a exaple tablea is on servera and tableb is on serverb . – Johny Arduino Jan 28 '17 at 07:38
  • If that's what you want, why don't you want to use linked servers, which is Microsoft's (very good) way of doing this, and is designed for the task? It is far superior to anything you are likely to be able to put together yourself, with or without help from SO. – MartynA Jan 28 '17 at 08:13
  • @IoannisYpatidis: I've posted an update to my answer to show how to do what you said you want, without using linked servers. – MartynA Jan 28 '17 at 09:04
  • Hi , I agree MS linked servers is working very well. Thanks everybody for the tips! – Johny Arduino Jan 28 '17 at 12:42
  • @IoannisYpatidis: The ClientDataSet-based solution I've added to my answer should be adequate if you are primarily interested in viewing data rather than changing it. Where MS Linked Servers really come into their own is where you need to carry out transactions across more than one server - afaik they use MS's Distributed Transaction Coordinator technology to make sure that either all the transaction components complete or non of them does. – MartynA Jan 28 '17 at 12:55
  • Hi MartynA! I have also tired the solution with the CDS and it works very well , till now. I would like to aks you also , how should I delete the data from the cdsMergedData CDS if this is not connected to anything , and I am doing eveything dynamically? – Johny Arduino Jan 30 '17 at 12:42
  • @IoannisYpatidis "how should I delete the data from the cdsMergedData CDS?" Just call its `.Close` method. – MartynA Jan 30 '17 at 12:46
  • Thank you!! It works! It is really so simple if you know the component :) . But I think Embarcadero lacks from having a good manual for their components. Is there anywhere I can generally found good info about the delphi components? – Johny Arduino Jan 31 '17 at 07:37
  • The best resources I know for information about Delphi components are here and the Emba newsgroups : https://forums.embarcadero.com/category.jspa?categoryID=12 – MartynA Jan 31 '17 at 07:44
  • HI MartynA , I would also like to ask you , how can I make the proccess more quick when I have really larger database to read? For example 500.00 records? Also when I try to read so big tables it fails and gives me en exception of "invalid parameter EDBClient" . I have set the AdoConnection and Adoqery timeout to 3000sec . Can you give me any advice on this? – Johny Arduino Jan 31 '17 at 10:25
  • Sorry 500.000 records – Johny Arduino Jan 31 '17 at 11:29
  • Well, the TClientDataSet seems to hit a brick-wall, performance-wise at a few tens of thousands of records, so for 500K it isn't really the tool for the job. If you are using Linked Servers + ADO, ADO is usually fairly fast, but you seem to be wanting to break the golden rule of working with Sql Servers, namely to be as selective as you can possibly be in retrieving records, especially in view of the possible impact on other users of the server; always retrieve as few records and as few columns as possible. So if you are doing a "select * from sometable" expect problems with large datasets. – MartynA Jan 31 '17 at 12:05
1

You could try this : FIREDAC LOCALSQL

It works like a charm. but pay attention to

  1. I'm not sure if it works for XE7. You have to check it. In Seatle it is available.
  2. Can't recommend it for huge data. 3-4 thousand records may come to be slow.
  3. I know about one bug. when making SUM(FIELD) and use Group by by some reason sum come to be string field.
Ilia C
  • 11
  • 1