U++ framework
Do not panic. Ask here before giving up.

Home » U++ Library support » U++ SQL » How to display fields from different tables in one SQLArray
How to display fields from different tables in one SQLArray [message #18765] Mon, 20 October 2008 14:14 Go to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

How to display fields from different tables in one SQLArray.
Are there any analog View-Join

There are 2 tables:

TABLE_(PROJECT)
INT_ (PR_ID) PRIMARY_KEY AUTO_INCREMENT
INT_ (PR_CREATIONDATE)
INT_ (PR_USERID)
INT_ (PR_COMPANYID)
STRING_ (PR_TASKTODO,2000)
DOUBLE_ (PR_SUM)
INT_ (PR_PLANNEDDELIVERYDATE)
DOUBLE_ (PR_SUMFACT)
INT_ (PR_STATUS)
INT_ (PR_PAYSTATUS)
INT_ (PR_PLANNEDEXECUTIONTIME)
STRING_ (PR_COMMENT,2000)
END_TABLE

and

TABLE_(COMPANY)
INT_ (COM_ID) PRIMARY_KEY AUTO_INCREMENT
INT_ (COM_GROUPID)
STRING_ (COM_NAME,2000)
STRING_ (COM_INN,2000)
STRING_ (COM_KPP,2000)
STRING_ (COM_ADDRESSDOC,2000)
STRING_ (COM_ADDRESSFACT,2000)
STRING_ (COM_COMMENT,2000)
END_TABLE

They relate by field PR_COMPANYID

I need to display the first table, and instead of field PR_COMPANYID I need to display COM_NAME from second table. I found 2 solutions. First - do Join View on the SQL server. Second - do converter to display the column in the table. I think that there should be a 3rd - Correct.

Please Give the right decision.


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18766 is a reply to message #18765] Mon, 20 October 2008 14:20 Go to previous messageGo to next message
zsolt is currently offline  zsolt
Messages: 702
Registered: December 2005
Location: Budapest, Hungary
Contributor
I use simple ArrayCtrl to show this type of query results.

See SqlArray source to find out, how to create a select, based on ArrayCtrl columns.
Re: How to display fields from different tables in one SQLArray [message #18769 is a reply to message #18766] Mon, 20 October 2008 14:28 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

Could you give simple example?

SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18771 is a reply to message #18769] Mon, 20 October 2008 14:55 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

Maybe there is method to achieve the same result using SqlArray?

SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18785 is a reply to message #18769] Mon, 20 October 2008 22:51 Go to previous messageGo to next message
zsolt is currently offline  zsolt
Messages: 702
Registered: December 2005
Location: Budapest, Hungary
Contributor
First you have to add the fields to your arrayctrl:
m_array.AddKey(PR_ID); //primary key
m_array.AddColumn(PR_CREATIONDATE, t_("Creation Date"), 10)
    .SetConvert(Single<ConvertYourIntBasedDate>());
...
m_array.AddColumn(COM_NAME, t_("Company Name"), 10);
...


You have to have a function returning the fields of your Select statement:
SqlSet GetSqlColumns(const ArrayCtrl &a_array)
{
	SqlSet cols;
	for(int i = 0; i < a_array.GetIndexCount(); i++)
		if(!a_array.GetId(i).IsNull())
			cols.Cat(SqlId(a_array.GetId(i)));
	return cols;
}


And a code to fill the arrayctrl from db:
SqlSet cols = GetSqlColumns(m_array);
Sql sql;
sql * ::Select(Distinct(cols))
	.From(PROJECT)
	.LeftJoin(COMPANY)
	.On(COM_ID == PR_COMPANYID)
	.Where(1)
	.OrderBy(PR_ID)
;

for(;;) {
	Vector<Value> row;
	if(!sql.Fetch(row)) break;
	m_array.Add(row);
}

Re: How to display fields from different tables in one SQLArray [message #18786 is a reply to message #18785] Mon, 20 October 2008 23:00 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

Thanks

SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18787 is a reply to message #18786] Mon, 20 October 2008 23:04 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

Does works methods like like Query(), Requery().???

SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18949 is a reply to message #18787] Sun, 02 November 2008 14:12 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

Maybe I need GridControl ?

Can GridControl show in different columns data from related tables (child-parent)?

How to do this??


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18963 is a reply to message #18787] Sun, 02 November 2008 16:47 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14290
Registered: November 2005
Ultimate Member
sergeynikitin wrote on Mon, 20 October 2008 17:04

Does works methods like like Query(), Requery().???


No. You have to implement them yourself. But it is quite simple.

Mirek
Re: How to display fields from different tables in one SQLArray [message #18964 is a reply to message #18963] Sun, 02 November 2008 16:54 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

I have a huge table 50000-100000 records. It involves 12-15 reference tables. This is stored in the MySQL server.

What kind of technology would you recommend to work with the database.

Will all the data loaded into memory or the client program will be loaded only a fraction?


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18965 is a reply to message #18964] Sun, 02 November 2008 19:09 Go to previous messageGo to next message
unodgs is currently offline  unodgs
Messages: 1367
Registered: November 2005
Location: Poland
Ultimate Contributor

sergeynikitin wrote on Sun, 02 November 2008 10:54

I have a huge table 50000-100000 records. It involves 12-15 reference tables. This is stored in the MySQL server.

What kind of technology would you recommend to work with the database.

Will all the data loaded into memory or the client program will be loaded only a fraction?


Loading it all would make your app working very slow. In my current app (Postgres) I use offset limit to page data. And of course I implemented special toolbar for navigating:
index.php?t=getfile&id=1464&private=0
In SqlServer you can use OVER and ROW_NUMBER() to do the same.
  • Attachment: nav.png
    (Size: 1.86KB, Downloaded 1711 times)
Re: How to display fields from different tables in one SQLArray [message #18966 is a reply to message #18965] Sun, 02 November 2008 19:41 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

That is, in short, GridCtrl download the entire table in memory of the client, and does not limit the recording while watching?

And is there any way to avoid this unpleasant fact and load only those records that are visible on the screen, and then as we move curdor row on the table load on one record, or any small portions?

Maybe there is a method or a callback, in which I can do this functionality to the SqlArray.


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18969 is a reply to message #18966] Sun, 02 November 2008 20:44 Go to previous messageGo to next message
unodgs is currently offline  unodgs
Messages: 1367
Registered: November 2005
Location: Poland
Ultimate Contributor

No, GridCtrl doesn't download entire table into memory. In fact it dosn't load anything itself Wink. Just told you how I deal with large tables. When user press second page I load only that page into memory. Numbers of page rows is also determined by user.
Dynamic loading during scrolling is imo a bad idea. Your ui actions will be "delayed" while loading next portion of rows. Of course you can load data when scrollbar's thumb stops moving, but it implies the next problem - what will you show to the user during scrolling action?
Re: How to display fields from different tables in one SQLArray [message #18973 is a reply to message #18969] Sun, 02 November 2008 21:50 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

unodgs wrote on Sun, 02 November 2008 22:44

Of course you can load data when scrollbar's thumb stops moving, but it implies the next problem - what will you show to the user during scrolling action?


If you say about scrollbar position than it's no problem. We are know quantity of rows in whole table and we can calculate rihgt position of sb.

And on the position of SB, we can calculate the position in the table to display.

Of course it is, I suppose. Ideally.



SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18974 is a reply to message #18964] Sun, 02 November 2008 21:55 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14290
Registered: November 2005
Ultimate Member
sergeynikitin wrote on Sun, 02 November 2008 10:54

I have a huge table 50000-100000 records. It involves 12-15 reference tables. This is stored in the MySQL server.

What kind of technology would you recommend to work with the database.

Will all the data loaded into memory or the client program will be loaded only a fraction?



Just a funny note: I have just tried what it takes to fetch 130000 records to ArrayCtrl.

It is about 400MB.

Therefore, I would recommend trying the simple path first - do not worry and try it. Maybe the table is not as huge as you think.

You know it, "premature optimization..."

(Well, it definitely is not a huge table. The biggest table I am regulary dealing with has 2 500 000 records Smile

Mirek

[Updated on: Sun, 02 November 2008 21:56]

Report message to a moderator

Re: How to display fields from different tables in one SQLArray [message #18975 is a reply to message #18973] Sun, 02 November 2008 21:58 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

There is a proprietary product TopSpeed Clarion.

When I first tried IDE Ultimate + +. I saw a lot of similarities with the Clarion.

In Clarion just used this approach to display the huge tables (but not huge, too), when the client receives from the server only lines that appear on the screen at the moment.

Of course it is difficult to program, but it works quite quickly.


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #18976 is a reply to message #18969] Sun, 02 November 2008 21:59 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14290
Registered: November 2005
Ultimate Member
unodgs wrote on Sun, 02 November 2008 14:44


Of course you can load data when scrollbar's thumb stops moving, but it implies the next problem - what will you show to the user during scrolling action?



Actually, shadow areas that get updated as soon as rows get fetched in would not look that bad Smile (I am using similar principle in RichEdit when rescaling window with images).

Mirek
Re: How to display fields from different tables in one SQLArray [message #18977 is a reply to message #18975] Sun, 02 November 2008 22:01 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14290
Registered: November 2005
Ultimate Member
sergeynikitin wrote on Sun, 02 November 2008 15:58

There is a proprietary product TopSpeed Clarion.

When I first tried IDE Ultimate + +. I saw a lot of similarities with the Clarion.

In Clarion just used this approach to display the huge tables (but not huge, too), when the client receives from the server only lines that appear on the screen at the moment.

Of course it is difficult to program, but it works quite quickly.


IMO, the problem is that there is no generic way how to create random access cursor to all suported RDMBs... AFAIK.

OTOH, maybe this is something to investigate.

Mirek
Re: How to display fields from different tables in one SQLArray [message #18978 is a reply to message #18976] Sun, 02 November 2008 22:09 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

By the way, I have decided to how to display related fields from other tables by using SqlArray.

struct ConvCompany : Convert
{
        Value Format(const Value &q) const
        {
			SQL * Select(COM_NAME).From(COMPANY).Where(COM_ID == q);
			String company;
			if(SQL.Fetch())
				company = SQL[COM_NAME];
			else
				company = "";
			return q.IsNull() ? Null : company;
        }
};

.....
.....

projects.AddColumn(VPR_COMPANYID, t_("Customer")).SetConvert(Single<ConvCompany>());


This method is bad because they occur too frequent recourse to the server, but the program looks beautiful.


It would be good to do the same method could display LEFT JOINED FIELD.

Maybe this way:
projects.SetTable(PROJECTV),Leftjoined(COMPANY,VPR_COMPANYID),AS_PREFIX(VCOM_);
projects.AddColumn(VCOM_COMPANYNAME, t_("Customer"));


This is the ideal, or something similar.



SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}

[Updated on: Sun, 02 November 2008 22:19]

Report message to a moderator

Re: How to display fields from different tables in one SQLArray [message #19110 is a reply to message #18978] Wed, 12 November 2008 22:23 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14290
Registered: November 2005
Ultimate Member
sergeynikitin wrote on Sun, 02 November 2008 16:09

By the way, I have decided to how to display related fields from other tables by using SqlArray.

[code]
struct ConvCompany : Convert
{
Value Format(const Value &q) const
{
SQL * Select(COM_NAME).From(COMPANY).Where(COM_ID == q);
String company;
if(SQL.Fetch())
company = SQL[COM_NAME];
else
company = "";
return q.IsNull() ? Null : company;
}
};



WARNING: Fetching from SQL ("SQL.Fetch()") is NOT RECOMMENDED (based on expriences:)

It is way too simple to call something in the fetch loop which will issue different SQL statment through SQL.

Use "Sql sql; sql * Select....; sql.Fetch()" instead.

Considering efficiency, IME, this method is usually still passable - one reason is that ArrayCtrl converts only if it needs to Paint it, so if the table has 10000 rows, for the first user action, only about 30 selects are performed.

You can also help it a bit by using "Cache" column modified - in that case, for particular ArrayCtrl cell, Convert is only invoked once, then the converted value is cached. That, obviously, has disadvantages of its own, but usually is harmless.

If you need to be more efficient, you can also use WhenPostQuery or something like that to prefetch all values you need for conversion. E.g. this is direct excerpt from my current job, where I have to solve quite similar problem:

struct NameConvert : Convert {
	VectorMap<int, String> name;
	VectorMap<int, String> surname;
	virtual Value Format(const Value& q) const;
	void LoadAttrs();
};

Value NameConvert::Format(const Value& q) const
{
	return surname.Get(q, String()) + ' ' + name.Get(q, String());
}

void NameConvert::LoadAttrs()
{
	name.Clear();
	surname.Clear();
	Sql sql;
	sql * Select(SUBJECT_ID, ATTR, TEXT).From(SUBJECT_ATTR)
	      .OrderBy(Descending(Nvl(TILL, Date::High())));
	while(sql.Fetch()) {
		int sid = sql[SUBJECT_ID];
		String id = sql[ATTR];
		if(id == "NAME" && name.Find(sid) < 0)
			name.Add(sid, sql[TEXT]);
		if(id == "LASTNAME" && surname.Find(sid) < 0)
			surname.Add(sid, sql[TEXT]);
	}
}


Quote:


Maybe this way: [code]
projects.SetTable(PROJECTV),Leftjoined(COMPANY,VPR_COMPANYID ),AS_PREFIX(VCOM_);
projects.AddColumn(VCOM_COMPANYNAME, t_("Customer"));

This is the ideal, or something similar.



I will think about it.

However, 85% of SqlArray code is dealing with insert/update/edit, which would not apply here (IMO). You can easily reimplement those 15% as special case quite easily IMO.

Mirek
Re: How to display fields from different tables in one SQLArray [message #19120 is a reply to message #19110] Thu, 13 November 2008 11:26 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

luzr wrote on Thu, 13 November 2008 00:23

sergeynikitin wrote on Sun, 02 November 2008 16:09

By the way, I have decided to how to display related fields from other tables by using SqlArray.

[code]
struct ConvCompany : Convert
{
Value Format(const Value &q) const
{
SQL * Select(COM_NAME).From(COMPANY).Where(COM_ID == q);
String company;
if(SQL.Fetch())
company = SQL[COM_NAME];
else
company = "";
return q.IsNull() ? Null : company;
}
};




WARNING: Fetching from SQL ("SQL.Fetch()") is NOT RECOMMENDED (based on expriences:)

It is way too simple to call something in the fetch loop which will issue different SQL statment through SQL.

Use "Sql sql; sql * Select....; sql.Fetch()" instead.






What do you mean? What is the difference between SQL and sql?
In my app I use this initialization code:
	MySqlSession session;
	if(!session.Connect(app.mysql_username, app.mysql_password, app.mysql_database, app.mysql_server)) {
		printf("Can't connect with MySql\n");
		PromptOK(t_("Can't connect with MySql"));
		return;
	}
	mysql_set_character_set(session, "utf8");
	
	SQL = session;
	Sql sql(session);

If you can - I want a short comment about the differences of my decision and your.

Yes. perhaps this is the best solution - to write complex pieces by hands.

By the way, thanks for the complex example.


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #19152 is a reply to message #19120] Sat, 15 November 2008 15:02 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14290
Registered: November 2005
Ultimate Member
sergeynikitin wrote on Thu, 13 November 2008 05:26


What do you mean? What is the difference between SQL and sql?



I mean that SQL is global variable (well, technically, it is more comlicated, but it behaves just like global variable).

And the inherent problem with global variables is that they are problem in reentrant code.

void Sum(int id) {
  return SQL % Select(SqlSum(MONEY)).From(TABLE).Where(ID == id);
}

void PrintSums() {
  SQL * Select(NAME, MONEY_ID).From(TABLE);
  while(SQL.Fetch())
     Print(SQL[NAME], Sum(SQL[MONEY_ID]);
}


I have made this bug way too many times -> that is why I always have to warn about fetching from SQL.

Quote:


	MySqlSession session;
	if(!session.Connect(app.mysql_username, app.mysql_password, app.mysql_database, app.mysql_server)) {
		printf("Can't connect with MySql\n");
		PromptOK(t_("Can't connect with MySql"));
		return;
	}
	mysql_set_character_set(session, "utf8");
	
	SQL = session;
	Sql sql(session);




This corrent and in fact, you do not need to repeat

Sql sql(session);

because

Sql sql;

is the same as

Sql sql(SQL.GetSession());

There are two purposes for SQL - to serve as simple cursor for inster/delete/update and inline fetches AND to represent default global database connection so that you do not need to repeat 'session' all the time.

Just do not do explicit fetches from it, because while technically possible, it is a sure way how to shoot you leg:)

Mirek
Re: How to display fields from different tables in one SQLArray [message #19154 is a reply to message #19152] Sat, 15 November 2008 15:48 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

I understand the idea and faced similar issues in other environments.

And the solution is produced in general is simple and beautiful.

Just forget about the context reentrant.

Thanks for comment.


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #20493 is a reply to message #19154] Fri, 20 March 2009 17:06 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

I went on the road, proposed in a previous message, and came across an odd job VectorMap. Here is a piece of code.


Value ConvNomencl::Format(const Value& q) const
{
	static VectorMap<int, String> nom;
	static Time lastcleartime;
	if(GetSysTime()-lastcleartime > 60){
		nom.Clear();
		lastcleartime=GetSysTime();
	}
	if(nom.GetCount()==0) nom.Add(0, " "); // <==adding empty entry there. 
	int q1=q;
	int f = nom.Find(q1);
	if(f > 0){
		String s;
		s = nom.Get(q1);
		return s;
	} else {
		Sql sql;
		sql * SqlSelect(NOM_ID,NOM_NAME).From(NOMENCL).Where(NOM_ID == q);
		String nomencl;
		if(sql.Fetch()) {
			int sid = sql[NOM_ID];
			nom.Add(sid, sql[NOM_NAME]);
			nomencl = sql[NOM_NAME];
		} else {
			nomencl = "";
		}
		return nomencl;
	}
}


After creating or cleaning object VectorMap, the first added item can not be found by .Find() method, and therefore the number of elements corresponding to the first element is continuously growing.

However, if you add the first empty element - then all the rest are working properly. This is well intended, or is it wrong?


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #20498 is a reply to message #18765] Fri, 20 March 2009 21:37 Go to previous messageGo to next message
mr_ped is currently offline  mr_ped
Messages: 826
Registered: November 2005
Location: Czech Republic - Praha
Experienced Contributor
if (f > 0) ?
Find returns position of element (0..N-1) or negative value if not found.

See http://www.ultimatepp.org/src$Core$AMap$en-us.html#AMap..cla ss
Re: How to display fields from different tables in one SQLArray [message #20501 is a reply to message #20498] Sat, 21 March 2009 08:04 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

Oh!!! yes !!!

Thanks.. Razz


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: How to display fields from different tables in one SQLArray [message #22348 is a reply to message #20501] Tue, 07 July 2009 09:47 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

I want to say a special thank you for the construction with prefixes s_.

When many tables (about 5-10) with the same fields, the fields were named as NOM_NAME ED_NAME COM_NAME ...
And especially when the database is not mine and I can not rename a fields.

Overall, an excellent solution !


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
template + convert problem [message #23153 is a reply to message #22348] Sat, 19 September 2009 14:22 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

I make a table in which multiple fields of reference from other tables. The mapping of the field from another table I made with the converter.

Now it looks as follows:

converts.h

struct ConvCompany : Convert
{
	virtual Value Format(const Value& q) const;
};

struct ConvNomencl : Convert
{
	virtual Value Format(const Value& q) const;
};

struct ConvManager : Convert
{
	virtual Value Format(const Value& q) const;
};


converts.cpp:
Value ConvCompany::Format(const Value &q) const
{
	if(q.IsNull()) return Null;
	static VectorMap<int, String> comp;
	static Time lastcleartime;
	if(GetSysTime()-lastcleartime > 600){
		comp.Clear();
		lastcleartime=GetSysTime();
	}
	int f = comp.Find(int(q));
	if(f >= 0){
		return comp[f];
	} else {
		Sql sql;
		sql * Select(COM_NAME).From(COMPANY).Where(COM_ID == q);
		String company;
		if(sql.Fetch()) {
			int sid = int(q);
			company = sql[COM_NAME];
			comp.Add(sid, company);
		} else {
			company = "";
		}
		return company;
	}
}
Value ConvNomencl::Format(const Value& q) const
{
	if(q.IsNull()) return Null;
	static VectorMap<int, String> nom;
	static Time lastcleartime;
	if(GetSysTime()-lastcleartime > 600){
		nom.Clear();
		lastcleartime=GetSysTime();
	}
	int f = nom.Find(int(q));
	if(f >= 0){
		return nom[f];
	} else {
		Sql sql;
		sql * SqlSelect(NOM_ID,NOM_NAME).From(NOMENCL).Where(NOM_ID == q);
		String nomencl;
		if(sql.Fetch()) {
			int sid = sql[NOM_ID];
			nomencl = sql[NOM_NAME];
			nom.Add(sid, nomencl);
		} else {
			nomencl = "";
		}
		return nomencl;
	}
}

Value ConvManager::Format(const Value &q) const
{
	if(q.IsNull()) return Null;
	static VectorMap<int, String> man;
	static Time lastcleartime;
	if(GetSysTime()-lastcleartime > 600){
		man.Clear();
		lastcleartime=GetSysTime();
	}
	int f = man.Find(int(q));
	if(f >= 0){
		return man[f];
	} else {
		Sql sql;
		sql * SqlSelect(USR_REALNAME).From(USER).Where(USR_ID == q);
		String manager;
		if(sql.Fetch()) {
			int sid = int(q);
			manager = sql[USR_REALNAME];
			man.Add(sid, manager);
		} else {
			manager = "";
		}
		return manager;
	}
}


These converters differ only in the name of the table and field names. I want this to be in the form of a template, something like:
template <SqlId TBL ,SqlId ID, SqlId NAME,int CLEARTIME>
struct ConvDict : Convert
//ConvDict<COMPANY,COM_ID,COM_NAME,600>()
{
	virtual Value Format(const Value& q) const {
		if(q.IsNull()) return Null;
		static VectorMap<int, String> dict;
		static Time lastcleartime;
		if(GetSysTime()-lastcleartime > CLEARTIME){
			dict.Clear();
			lastcleartime=GetSysTime();
		}
		int f = dict.Find(int(q));
		if(f >= 0){
			return dict[f];
		} else {
			Sql sql;
			sql * Select(NAME).From(TBL).Where(ID == q);
			String s;
			if(sql.Fetch()) {
				int sid = int(q);
				s = sql[NAME];
				dict.Add(sid, s);
			} else {
				s = "";
			}
			return s;
		}
	}
};


But this code is not compiled, wrote that at this point can not be applied SqlId.

Can someone experienced with this?

How do make a template for the Converter, or Display?


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: template + convert problem [message #23154 is a reply to message #23153] Sat, 19 September 2009 19:30 Go to previous messageGo to next message
Zbych is currently offline  Zbych
Messages: 332
Registered: July 2009
Senior Member
sergeynikitin wrote on Sat, 19 September 2009 14:22

The mapping of the field from another table I made with the converter.


Can you tell me why you didn't use 'join', 'where' or 'view', to connect those tables?
Re: template + convert problem [message #23155 is a reply to message #23154] Sat, 19 September 2009 19:59 Go to previous messageGo to next message
andrei_natanael is currently offline  andrei_natanael
Messages: 262
Registered: January 2009
Experienced Member
You don't really need a template for this. You may create a setter and initialize the converter with proper values. Something like...
struct ConvDict : Convert
{
    SqlId TBL ,ID, NAME, CLEARTIME;
public:
    void setValues(SqlId _TBL ,SqlId _ID, SqlId _NAME,int _CLEARTIME)
    {
        TBL = _TBL;
        ID = _ID;
        NAME = _NAME;
        CLEARTIME = _CLEARTIME;
    }
// ...

The only inconvenient is that you have to call setValues before using converter.

[Updated on: Sat, 19 September 2009 20:20]

Report message to a moderator

Re: template + convert problem [message #23156 is a reply to message #23154] Sat, 19 September 2009 22:37 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

Zbych wrote on Sat, 19 September 2009 21:30

sergeynikitin wrote on Sat, 19 September 2009 14:22

The mapping of the field from another table I made with the converter.


Can you tell me why you didn't use 'join', 'where' or 'view', to connect those tables?



The reasons may be several:
1. SqlArray is not support join
2. This method saves SQL trafic and network speed on Huge Database.
3. View may not be fully compatible with some database engine.


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: template + convert problem [message #23157 is a reply to message #23155] Sat, 19 September 2009 22:45 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

andrei_natanael wrote on Sat, 19 September 2009 21:59

You don't really need a template for this. You may create a setter and initialize the converter with proper values. Something like...
struct ConvDict : Convert
{
    SqlId TBL ,ID, NAME, CLEARTIME;
public:
    void setValues(SqlId _TBL ,SqlId _ID, SqlId _NAME,int _CLEARTIME)
    {
        TBL = _TBL;
        ID = _ID;
        NAME = _NAME;
        CLEARTIME = _CLEARTIME;
    }
// ...

The only inconvenient is that you have to call setValues before using converter.


template is interesting because you can create separate converters for different reference tables designating the tables at the time of use in the code.
(I once again repeat - a lot of reference tables, and many links to them from the main table.)


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: template + convert problem [message #23163 is a reply to message #23156] Sun, 20 September 2009 15:47 Go to previous messageGo to next message
Zbych is currently offline  Zbych
Messages: 332
Registered: July 2009
Senior Member
sergeynikitin wrote on Sat, 19 September 2009 22:37

The reasons may be several:
1. SqlArray is not support join



You can always connect tables using 'where', or just use 'join' + ArrayCtrl and fill it "manually". It is simpler than your solution.

Quote:


2. This method saves SQL trafic and network speed on Huge Database.



If you have huge database, than you usually don't display everything at once. Beside, I guess, it is faster to send one query with 1000 rows, that 1000 queries with 1 row each.


Quote:


3. View may not be fully compatible with some database engine.


Than you should use databases, that supports views.

[Updated on: Sun, 20 September 2009 15:48]

Report message to a moderator

Re: template + convert problem [message #23169 is a reply to message #23163] Mon, 21 September 2009 07:34 Go to previous messageGo to next message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

Zbych wrote on Sun, 20 September 2009 17:47



Quote:


2. This method saves SQL trafic and network speed on Huge Database.



If you have huge database, than you usually don't display everything at once. Beside, I guess, it is faster to send one query with 1000 rows, that 1000 queries with 1 row each.


Quote:


3. View may not be fully compatible with some database engine.


Than you should use databases, that supports views.



What's about decision for notebook+mobile phone. If I use converters, theò users almost do not notice a slow connection, because each row of the table passed 5 integer numbers.

If I use a view or LeftJoin, then each row of the table must be sent to 100 bytes (5 fields of 20 bytes), that is slower to 10 times.


SergeyNikitin<U++>( linux, wine )
{
    under( Ubuntu || Debian || Raspbian );
}
Re: template + convert problem [message #44632 is a reply to message #23169] Thu, 30 April 2015 07:55 Go to previous message
sergeynikitin is currently offline  sergeynikitin
Messages: 748
Registered: January 2008
Location: Moscow, Russia
Contributor

I've made this template!!!

Universal Lookup Convertor syntax like this:
(Single<ConvLookup<COMPANY,COM_ID,COM_NAME> >() )


Let's test:

dict.h
template<typename T> T& LookupSetup ( T& grid, SqlId& tablename, SqlId& colid, SqlId& colname, bool showid = false, bool valueiscode = true, SqlBool where = true );
template<>		DropGrid& LookupSetup ( DropGrid& grid, SqlId& tablename, SqlId& colid, SqlId& colname, bool showid, bool valueiscode, SqlBool where );
template<>		WithDropChoice<EditString>& LookupSetup ( WithDropChoice<EditString>& grid, SqlId& tablename, SqlId& colid, SqlId& colname, bool showid, bool valueiscode, SqlBool where );
template<>		DropList& LookupSetup ( DropList& grid, SqlId& tablename, SqlId& colid, SqlId& colname, bool showid, bool valueiscode, SqlBool where );

template<typename T> T& LookupSetup1 ( T& grid, SqlId& tablename, SqlId& colid, SqlId& colname1, SqlId& colname2, bool showid = false, bool valueiscode = true, SqlBool where = true );
template<>		DropGrid& LookupSetup1 ( DropGrid& grid, SqlId& tablename, SqlId& colid, SqlId& colname1, SqlId& colname2, bool showid, bool valueiscode, SqlBool where );
template<>		WithDropChoice<EditString>& LookupSetup1 ( WithDropChoice<EditString>& grid, SqlId& tablename, SqlId& colid, SqlId& colname1, SqlId& colname2, bool showid, bool valueiscode, SqlBool where );


template< SqlId &LookupTable, SqlId &LookupCode, SqlId &LookupValue, bool show_id=false >
struct ConvLookup : Convert
{
     Value Format ( const Value &q ) const
     {
          int sid = q;
          if ( q.IsNull() ){
               return Null;
          } else if ( q == 0 ) {
               return "";
          }
          
          static VectorMap<int, Value> valuecache;
          static Time lastcleartime;
          if ( GetSysTime() - lastcleartime > 600 )
          {
               valuecache.Clear();
               lastcleartime = GetSysTime();
          }
          if ( valuecache.Get ( sid, "X") != "X" )
          {
               if (show_id) {
                    return AsString ( sid ) + ": " + AsString(valuecache.Get ( sid, Value() ));
               } else {
                    return valuecache.Get ( sid, Value() );
               }
          }
          else
          {
               Sql sql;
               sql * Select ( LookupValue ).From ( LookupTable ).Where ( LookupCode == sid );
               if ( sql.Fetch() )
               {
                    valuecache.Add ( sid, AsString(sql[LookupValue]) );
                    if ( valuecache.Get ( sid, "X" ) != "X" )
                    {
                         if (show_id) {
                              return AsString ( sid ) + ": " + AsString(valuecache.Get ( sid, Value() ) );
                         } else {
                              return valuecache.Get ( sid, Value() );
                         }
                    }
                    return sql[LookupValue] ;
               }
               else
               {
                    return  AsString ( sid ) + ": ??? " + t_(~LookupTable) + " ???" ;
               }
          }
          return  "ERROR RETURN PLACE" ;
     }
};





dict.cpp
template<typename T> T& LookupSetup ( T& grid, SqlId& tablename, SqlId& colid, SqlId& colname, bool showid, bool valueiscode, SqlBool where ) {}

template<> DropGrid& LookupSetup ( DropGrid& grid, SqlId& tablename, SqlId& colid, SqlId& colname, bool showid, bool valueiscode, SqlBool where )
{
     Sql sql;

     if ( grid.GetList().GetColumnCount() == 0 )
     {
          grid.ClearButton();
          grid.Resizeable ( false );
          grid.AddColumn ( colid, "", showid ? 10 : 0, true );
          grid.AddColumn ( colname,  showid  ? " : " : "", 70 );

          if ( showid )
               grid.SetValueColumn ( 0 );
          else
               grid.SetValueColumn ( 1 );

          if ( valueiscode )
          {
               grid.SetKeyColumn ( 0 );
          }
          else
          {
               grid.SetKeyColumn ( 1 );
          }

          if ( showid )
          {
               grid.AddValueColumn ( 0 );
          }
          grid.AddValueColumn ( 1 );
          
          grid.SetFindColumn ( 1 );

          grid.NoHeader();

          grid.ColorRows();
     }

     grid.Clear();

     sql * Select ( colid,
                    colname ).From ( tablename ).Where ( where ).OrderBy ( colid );

     while ( sql.Fetch() )
     {
          grid.Add ( sql[colid], sql[colname] );
     }

     return grid;
}

template<> WithDropChoice<EditString>& LookupSetup ( WithDropChoice<EditString>& grid, SqlId& tablename, SqlId& colid, SqlId& colname, bool showid, bool valueiscode, SqlBool where )
{
     Sql sql;
     grid.ClearList();
     sql * Select ( colname ).From ( tablename ).Where ( where ).OrderBy ( colname );

     while ( sql.Fetch() )
     {
          grid.AddList ( sql[colname] );
     }

     return grid;
}

template<> DropList& LookupSetup ( DropList& grid, SqlId& tablename, SqlId& colid, SqlId& colname, bool showid, bool valueiscode, SqlBool where )
{
     Sql sql;

     if ( grid.GetList().GetColumnCount() == 0 )
     {
          grid.SetDropLines ( 12 );
     }

     grid.ClearList();

     sql * Select ( colname ).From ( tablename ).Where ( where ).OrderBy ( colname );

     while ( sql.Fetch() )
     {
          grid.Add ( sql[colname] );
     }

     return grid;
}


template<typename T> T& LookupSetup1 ( T& grid, SqlId& tablename, SqlId& colid, SqlId& colname1, SqlId& colname2, bool showid, bool valueiscode, SqlBool where ) {}

template<> DropGrid& LookupSetup1 ( DropGrid& grid, SqlId& tablename, SqlId& colid, SqlId& colname1, SqlId& colname2, bool showid, bool valueiscode, SqlBool where )
{
     Sql sql;

     if ( grid.GetList().GetColumnCount() == 0 )
     {
          grid.ClearButton();
          grid.Resizeable ( false );
          grid.AddColumn ( colid, "", showid ? 10 : 0, true );
          grid.AddColumn ( colname1, valueiscode ? " : " : "", 70 );
          grid.AddColumn ( colname2, "", 70 );
          if ( showid )
               grid.SetValueColumn ( 0 );
          else
               grid.SetValueColumn ( 1 );

          if ( valueiscode )
          {
               grid.SetKeyColumn ( 0 );
          }
          else
          {
               grid.SetKeyColumn ( 1 );
          }

          if ( showid )
          {
               grid.AddValueColumn ( 0 );
          }
          grid.AddValueColumn ( 1 );
          
          grid.SetFindColumn ( 1 );

          grid.NoHeader();

          grid.ColorRows();
     }

     grid.Clear();

     sql * Select ( colid,
                    colname1, colname2 ).From ( tablename ).Where ( where ).OrderBy ( colid );

     while ( sql.Fetch() )
     {
          grid.Add ( sql[colid], sql[colname1], sql[colname2] );
     }

     return grid;
}

template<> WithDropChoice<EditString>& LookupSetup1 ( WithDropChoice<EditString>& grid, SqlId& tablename, SqlId& colid, SqlId& colname1, SqlId& colname2, bool showid, bool valueiscode, SqlBool where )
{
     Sql sql;
     grid.ClearList();
     sql * Select ( colname1, colname2 ).From ( tablename ).Where ( where ).OrderBy ( colname1 );

     while ( sql.Fetch() )
     {
          grid.AddList ( AsString ( sql[colname1] ) + " " + AsString ( sql[colname2] ) );
     }

     return grid;
}



And in AddColumn if GridCtrl you may write as this:
listvisitor.AddColumn ( VISR_COMPANY_ID, t_("Company"), 265 ).SetConvert(Single<ConvLookup<COMPANY,COM_ID,COM_NAME> >()).HeaderAlignCenter();

[Updated on: Thu, 30 April 2015 07:57]

Report message to a moderator

Previous Topic: DBF crash error while writing record
Next Topic: PATCH/BUGFIX Oracle asTable Failure - Solution
Goto Forum:
  


Current Time: Sat Apr 25 19:49:58 GMT+2 2026

Total time taken to generate the page: 0.01252 seconds