Zum Inhalt springen

Suche mit 1-N Relation

Erstellt am 18. November 2005 · 26 Antworten · letzte Antwort am 28. Dezember 2007 · Seite 1 von 2

Tags: Datenbank, Frage

suitside ·

Hallo Zusammen,

ich habe eine Extension mit dem Kickstarter erstellt, die mir zu einer PLZ den entsprechenden Eintrag ausgeben soll. Das funktioniert auch wunderbar, aber jetzt komme ich nicht weiter:
Die Suche soll in der Tabelle 1 (N-1) den jeweiligen Eintrag aus der Tabelle 2 ausgeben. Ich glaube, dass ich dafür die pi_exec_query anpassen muss, bin mir aber nicht sicher, weil alle Versuche bis jetzt erfolglos geblieben sind.

Vielen dank im voraus

Gruß Conny

suitside ·

mmmhh, vielleicht nochmal ein bißchen genauer: Ich brauche folgende SQL-Abfrage und würde sie gerne nicht irgendwie, sondern im Sinne des Erfinders integrieren:

SELECT tx_table_1* FROM tx_table_1, tx_table_2 WHERE tx_table_2.zip = $sword AND tx_table_2.manager = tx_table_1.uid
suitside ·

ok, also...
ich hab mit dem Kickstarter eine Extension mit 2 Tabellen erstellt.

Tabelle 1
uid wert1 ...
3 xyz ...
4 xyz ...

Tabelle 2
uid wert rel
1 1234 3
2 1235 3
3 1236 4

Tabelle2.rel ist im Kickstarter als Database Relation zu Tabelle1.uid definiert.
Unter 'Frontend Plugins' hab ich bei 'If you have configured custom tables you can select one of the tables to list by default as an example:' Tabelle 2 ausgewählt.
Dadurch generiert der Kickstarter folgenden Code für die Ausgabe als Liste:

function listView($content,$conf)	{
		$this->conf=$conf;		// Setting the TypoScript passed to this function in $this->conf
		$this->pi_setPiVarDefaults();
		$this->pi_loadLL();		// Loading the LOCAL_LANG values
		$this->pi_USER_INT_obj=1;	// Configuring so caching is not expected. This value means that no cHash params are ever set. We do this, because it's a USER_INT object!
		$lConf = $this->conf["listView."];	// Local settings for the listView function

		if ($this->piVars["showUid"])	{	// If a single element should be displayed:
			$this->internal["currentTable"] = "tx_table_2";
			$this->internal["currentRow"] = $this->pi_getRecord("tx_table_2",$this->piVars["showUid"]);

			$content = $this->singleView($content,$conf);
			return $content;
		} else {
			$items=array(
				"1"=> $this->pi_getLL("list_mode_1","Mode 1"),
				"2"=> $this->pi_getLL("list_mode_2","Mode 2"),
				"3"=> $this->pi_getLL("list_mode_3","Mode 3"),
			);
			if (!isset($this->piVars["pointer"]))	$this->piVars["pointer"]=0;
			if (!isset($this->piVars["mode"]))	$this->piVars["mode"]=1;

				// Initializing the query parameters:
			list($this->internal["orderBy"],$this->internal["descFlag"]) = explode(":",$this->piVars["sort"]);
			$this->internal["results_at_a_time"]=t3lib_div::intInRange($lConf["results_at_a_time"],0,1000,1);		// Number of results to show in a listing.
			$this->internal["maxPages"]=t3lib_div::intInRange($lConf["maxPages"],0,1000,1);;		// The maximum number of "pages" in the browse-box: "Page 1", "Page 2", etc.
			$this->internal["searchFieldList"]="zip";
			$this->internal["orderByList"]="uid,zip";

				// Get number of records:
			$res = $this->pi_exec_query("tx_table_2",1);
			list($this->internal["res_count"]) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);

				// Make listing query, pass query to SQL database:
			$res = $this->pi_exec_query("tx_table_2");
			$this->internal["currentTable"] = "tx_table_2";

				// Put the whole list together:
			$fullTable="";	// Clear var;

				// Adds the search box:
			$fullTable.=$this->pi_list_searchBox();

				// Adds the whole list table
			$fullTable.=$this->pi_list_makelist($res);

				// Returns the content from the plugin.
			return $fullTable;
		}
	}

Jetzt möchte ich gerne mit pi_list_searchBox() Tabelle2.wert suchen und über die Relation Tabelle2.rel->Tabelle1.uid die Werte von Tabelle1 ausgeben.

Die SQL-Abfrage dafür steht oben, aber ich weiß nicht, wie genau ich die Funktion listView() modifizieren muss, damit er mir als Suchergebnis die Werte aus Tabelle 1 ausgibt und nicht die Werte aus Tabelle 2.

Vielen Dank!

suitside ·

es ist mir ja schon fast peinlich, aber meinst du, du kannst mir in diesem konkreten Fall sagen, welche Code-Teile ich jetzt ersetzen muss und welche rausfallen?

function listView($content,$conf)       {
                $this->conf=$conf;            // Setting the TypoScript passed to this function in $this->conf
                $this->pi_setPiVarDefaults();
                $this->pi_loadLL();          // Loading the LOCAL_LANG values
                $this->pi_USER_INT_obj=1;       // Configuring so caching is not expected. This value means that no cHash params are ever set. We do this, because it's a USER_INT object!
                $lConf = $this->conf["listView."];      // Local settings for the listView function

                if ($this->piVars["showUid"])   {  // If a single element should be displayed:
                        $this->internal["currentTable"] = "tx_table_2";
                        $this->internal["currentRow"] = $this->pi_getRecord("tx_table_2",$this->piVars["showUid"]);

                        $content = $this->singleView($content,$conf);
                        return $content;
                } else {
                        $items=array(
                                "1"=> $this->pi_getLL("list_mode_1","Mode 1"),
                                "2"=> $this->pi_getLL("list_mode_2","Mode 2"),
                                "3"=> $this->pi_getLL("list_mode_3","Mode 3"),
                        );
                        if (!isset($this->piVars["pointer"]))   $this->piVars["pointer"]=0;
                        if (!isset($this->piVars["mode"]))      $this->piVars["mode"]=1;

                                // Initializing the query parameters:
                        list($this->internal["orderBy"],$this->internal["descFlag"]) = explode(":",$this->piVars["sort"]);
                        $this->internal["results_at_a_time"]=t3lib_div::intInRange($lConf["results_at_a_time"],0,1000,1);              // Number of results to show in a listing.
                        $this->internal["maxPages"]=t3lib_div::intInRange($lConf["maxPages"],0,1000,1);;                // The maximum number of "pages" in the browse-box: "Page 1", "Page 2", etc.
                        $this->internal["searchFieldList"]="zip";
                        $this->internal["orderByList"]="uid,zip";

			$res = $GLOBALS['TYPO3_DB']->sql(TYPO3_db, 'SELECT tx_table_1* FROM tx_table_1, tx_table_2 WHERE tx_table_2.zip = '.$sword.' AND tx_table_2.manager = tx_table_1.uid ');
			while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
				echo $row['title'].'<br />';
			}

                                // Put the whole list together:
                        $fullTable="";  // Clear var;

                                // Adds the search box:
                        $fullTable.=$this->pi_list_searchBox();

                                // Adds the whole list table
                        $fullTable.=$this->pi_list_makelist($res);

                                // Returns the content from the plugin.
                        return $fullTable;
                }
        }

Wäre super nett, danke

boonkerz ·

Hallo,

Schau mal:

 * Executes a standard SELECT query for listing of records based on standard input vars from the 'browser' ($this->internal['results_at_a_time'] and $this->piVars['pointer']) and 'searchbox' ($this->piVars['sword'] and $this->internal['searchFieldList'])
	 * Set $count to 1 if you wish to get a count(*) query for selecting the number of results.
	 * Notice that the query will use $this->conf['pidList'] and $this->conf['recursive'] to generate a PID list within which to search for records.
	 *
	 * @param	string		The table name to make the query for.
	 * @param	boolean		If set, you will get a "count(*)" query back instead of field selecting
	 * @param	string		Additional WHERE clauses (should be starting with " AND ....")
	 * @param	mixed		If an array, then it must contain the keys "table", "mmtable" and (optionally) "catUidList" defining a table to make a MM-relation to in the query (based on fields uid_local and uid_foreign). If not array, the query will be a plain query looking up data in only one table.
	 * @param	string		If set, this is added as a " GROUP BY ...." part of the query.
	 * @param	string		If set, this is added as a " ORDER BY ...." part of the query. The default is that an ORDER BY clause is made based on $this->internal['orderBy'] and $this->internal['descFlag'] where the orderBy field must be found in $this->internal['orderByList']
	 * @param	string		If set, this is taken as the first part of the query instead of what is created internally. Basically this should be a query starting with "FROM [table] WHERE ... AND ...". The $addWhere clauses and all the other stuff is still added. Only the tables and PID selecting clauses are bypassed. May be depreciated in the future!
	 * @return	pointer		SQL result pointer
	 */
	function pi_exec_query($table,$count=0,$addWhere='',$mm_cat='',$groupBy='',$orderBy='',$query='')	{

Ich möchte dir den code nicht vorlegen.
Hier ist mal die Beschreibung der Funktion.
Damit solltest du eigendlich die Query zusammen bauen können durch ein bischen probieren.

Wichtig wäre in deinem Fall:
* @param mixed If an array, then it must contain the keys "table", "mmtable" and (optionally) "catUidList" defining a table to make a MM-relation to in the query (based on fields uid_local and uid_foreign). If not array, the query will be a plain query looking up data in only one table.

suitside ·

es funktioniert 🙂

zwar etwas anders als geplant und vielleicht nicht so ganz im Sinne des Erfinders aber es tut...yipii

function main($content,$conf)	{
		$this->conf=$conf;
		$this->pi_setPiVarDefaults();
		$this->pi_loadLL();
		$this->pi_USER_INT_obj=1;	// Configuring so caching is not expected. This value means that no cHash params are ever set. We do this, because it's a USER_INT object!

		$content =$this->pi_list_searchBox();
		$content .= $this->piVars[sword]."<br />";
		$sword = $this->piVars[sword];

		if($sword != "") {
			$res = $GLOBALS['TYPO3_DB']->sql(TYPO3_db, 'SELECT * FROM tx_table1, tx_table2 WHERE tx_table2.zip = '.$sword.' AND tx_table2.fieldmanager = tx_table1.uid');

			while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
	    		$content .= $row['name'].'<br />';
			}

  		}

		return $this->pi_wrapInBaseClass($content);
	}

über Verbesserungsvorschläge freue ich mich natürlich auch weiterhin 😉

steffenk ·

genau da lande ich auch immer, da mir diese mm-Beziehung von Typo3 völlig schleierhaft ist, vor allem wenn man die Beziehung viel einfacher in SQL formulieren kann.

Für einfache Abfragen geht das ja noch, aber bei komplexeren Joins etc. mach ich mir den SQL lieber selber.

@suitside - ist doch prima wenn es so funktioniert, der Code ist auch viel schlanker und übersichtlicher.

Ich empfehle Dir die extension ExtDevEval, da kannst Du am schnellsten den Syntax nachschauen ( oder forschen )

dfluess ·

Also ich stehe vor dem gleichen Problem. Nur bin ich wahrscheinlich noch erfahrungsärmer was Datenbanken betrifft. Das kommt davon, wenn ein Designer die Arbeit eines DB-Menschen übernehmen muss :o(

In meinem Fall.

Tabelle 1 enthält allgemeine Infos wie Titel und andere Daten.
Tabelle 2 enthält die Postleitzahlen und den Ort.
Ich muss nun eine oder mehrere Postleitzahlen einem Datensatz aus Tabelle 1 zuordnen.

Ich habe also in Tabelle 1 diese Database Relation zu Tabelle 2 gemacht und kann im BE wunderbar die PLZ zuordnen. Aber weiter scheitert es an der Darstellung in der Liste und natürlich der Suche nach der PLZ. Will heißen, statt der PLZ wird nur eine UID ausgegeben.

Nun hab ich versucht Deinen Code zu portieren. Aber mir fehlt leider das Wissen und die Zeit, mich Tagelang mit PHP-Grundwissen herumzuschlagen.

Vielleicht kannst Du mir aber noch ein wenig behilflich sein??

Die Suche soll also anhand der PLZ eine Trefferliste der Datensätze aus Tabelle 1 ausgeben. Wenn ich dann einen Datensatz auswähle, dann soll’s weiter zur Singl-Ansicht gehen.

Im Moment stehe ich noch mächtig auf dem Schlauch. 🙁

Stoneage ·

Das hier ist mächtiger:

'SELECT FROM tx_table1 join tx_table2 on tx_table1.uid = tx_table2.fieldmanager WHERE tx_table2.zip = '.addslashes($sword);
dfluess ·

ho ho ho 😉 wenn man weis damit umzugehen sicher.. Ich dümpele noch im Ansatz mit meinem obigen Problem.

Eine Frage: Gibt’s einen Schalter oder einen anderen Grund, warum ein debug nicht ausgegeben wird? Beispielsweise sollte "debug(array($query));" mir doch den kompletten String ausgeben. Es passiert aber rein gar nichts.

D.

Stoneage ·
'SELECT FROM tx_table1 join tx_table2 on tx_table1.uid = tx_table2.uid WHERE tx_table2.POSTLEITZAHL = '.addslashes($POSTLEITZAHL);
dfluess ·

Kann ich überhaupt nix mit anfangen, weil mir das Konstrukt Drumherum fehlt, bzw. noch das aus dem Kickstarter Plugin ist. Das passt mit dem nicht zusammen oder? Ich wüsste nicht was ich rausschmeißen und hinzufügen muss.

Langsam bezweifele ich, dass ich das dieses Jahr noch hinbekomme. Kommt davon, wenn man jemandem einen Gefallen tun möchte und eigentlich zu wenig Ahnung hat den kompletten Durchblick zu finden. Ich beschäftige mich leider zu selten mit DB-Abfragen.

Eigentlich möchte ich "nur" über das Plugin eine PLZ suchen, die über die Database Relation mit nem Datensatz einer anderen Tabelle verknüpft ist – finden, und mit Klick auf diesen Treffer in der Singl-Ansicht dieses Datensatzes landen. So was bringt ja der Kickstarter schon fast mit, nur halt nicht über eine zweite Tabelle. Wenn doch nur schon Weihnachten währe 😢

Stoneage ·

Wenn Du das in Typo3 mit MM-Tabellen gemacht hast, dann könnte es so funktionieren:

'SELECT FROM tx_table1 JOIN tx_table_MM on tx_table1.uid = tx_table_MM.uid JOIN tx_table2 on tx_table_2.uid = tx_table_MM.pid WHERE tx_table2.POSTLEITZAHL = '.addslashes($POSTLEITZAHL);

Wenn Du das ohne Umhängetabelle gemacht hast, dann versuch mal das hier:

'SELECT FROM tx_table1 WHERE tx_table1.uid IN (SELECT MM FROM tx_table2) AND  tx_table2.POSTLEITZAHL = '.addslashes($POSTLEITZAHL);
dfluess ·

aha und den String dann in die Variable '$query' schreiben? Damit das Plugin den Standard überschreibt?

Der String sieht super aus und das funktioniert sicher auch. Aber wie "verheirate" ich das mit einem Plugin, dass mit dem Kickstarter erstellt wurde und bereits eine Liste ausgibt?

Auf alle Fälle danke ich Dir für Deine Mühe!

D.