php, mysql abfrage mit mehrdimensionalem(?) ergebnis
schildi
- datenbank
hallo.
ich arbeite gerade an einer abfrage, die ein ergebnis-array folgender art erzeugen soll:
$erg =
array
(
'erg1' =>
array(
'erg1a' => X
'erg2b' => X
'erg1c' => X
)
'erg2' =>
array(
'erg1b' => X
'erg1d' => X
)
'erg3' =>
array( ... )
...
)
ich gehe hierzu so vor, dass ich eine abfrage mit 'group by spalte1, spalte2' vornehme, und sortiere danach das suchergebnis per php-schleife über array-schlüssel in das $erg-array ein. gleiche array-schlüssel werden dann ja automatisch zusammengefasst.
das sql-ergebnis sieht also beispielhaft so aus:
erg1 | erg1a | X
erg1 | erg1b | X
erg1 | erg1c | X
erg2 | erg1b | X
erg2 | erg1d | X
...
nun habe ich das problem, dass mein ergebnis, welches ich durch den php-schleifendurchgang erzeuge in der ergebnis-zeilenanzahl nicht mit dem originalen sql-ergebnis übereinstimmt.
ich muss vor erzeugung des eigentlichen suchergebnisses jedoch noch eine abfrage machen, wie viele datensätze, das ergebnis der sql-abfrage haben wird (wegen ergebnisseiten-darstellung). dies möchte ich gerne mit einem count(distinct *) erledigen, jedoch kann ich ja meines wissens kein group-by über 2 spalten über dieses count(distinct ...) abbilden?
kurz gesagt, ich will die anzahl der ergebniszeilen des folgenden SQL's vor der eigentlichen ausführung (am bestena ja über ein count(...)) abfragen:
SELECT a.*,
b.*,
c.*,
d.*,
e.platform_id, e.name AS platform_name, e.abbreviation AS platform_abbreviation, e.logo_url AS platform_logo_url, e.platform_type, e.img_logo_small AS platform_img_logo_small,
g.option_id, g.name AS option_name
FROM funds a
LEFT JOIN fund_companies b ON a.company_id = b.company_id
CROSS JOIN fund_company_alias_name c ON b.fund_company_alias_name_id = c.fund_company_alias_name_id
LEFT JOIN fund_platform_fund_availability d ON a.isin = d.isin
LEFT JOIN fund_platforms e ON d.platform_id = e.platform_id
LEFT JOIN fund_extending_options_availability f ON a.isin = f.isin
LEFT JOIN fund_extending_options g ON f.option_id = g.option_id
WHERE b.activated = 'Y'
GROUP BY a.isin, e.platform_id
ORDER BY a.name ASC
LIMIT 0, 25
ausserdem noch meine frage, ob man ein derartiges sql-ergebnis, wie ich es im endeffekt haben möchte (siehe php-array) auch anders - evtl. direkt mit mysql oder auf eine geschicktere art und weise hinbekommen könnte.
yo,
ich habe nicht alles verstanden, was du machen willst. aber deine abfrage ist "mysql-schrott", um es mal ein wenig härer auszudrücken, sprich alle anderen dbms würden dir bei dieser abfrage ein fehlermeldung ausgeben. mysql verfolgt dort eine andere strategie, die aber zu mehr problemen als lösungen führt.
grundsätzlich ist es so, dass du nur spalten ausgeben kannst, über die auch gruppiert wurde oder aber die aggregat-funktionen benutzen. zum anderen kommt mir deine joins auf den ersten blick merkwürdig vor, aber vielleicht hat es ja auch einen sinn, der mir verborgen bleibt.
ich sclage vor, du gibst uns die betroffenen tabellen mit beispieldatensätzen und dann das genau ergebnis, dass du haben willst, am besten auch ohne irgend welchen php code.
Ilja
yo,
ich habe nicht alles verstanden, was du machen willst. aber deine abfrage ist "mysql-schrott", um es mal ein wenig härer auszudrücken, sprich alle anderen dbms würden dir bei dieser abfrage ein fehlermeldung ausgeben. mysql verfolgt dort eine andere strategie, die aber zu mehr problemen als lösungen führt.
erklär doch bitte mal genauer, wie genau du auf diesen schluß kommst.
das das datenbank-design schlecht ist weiss ich, das habe ich vor jahren ohne großes grundwissen entworfen gehabt und soll dummerweise heute noch herhalten.
grundsätzlich ist es so, dass du nur spalten ausgeben kannst, über die auch gruppiert wurde oder aber die aggregat-funktionen benutzen. zum anderen kommt mir deine joins auf den ersten blick merkwürdig vor, aber vielleicht hat es ja auch einen sinn, der mir verborgen bleibt.
hat vielleicht mit dem oben angesprochenen schlechten design zu tun..
ich sclage vor, du gibst uns die betroffenen tabellen mit beispieldatensätzen und dann das genau ergebnis, dass du haben willst, am besten auch ohne irgend welchen php code.
die tabellendefinitionen habe ich mal untenstehend reinkopiert.
was die daten angeht, wäre das hier zu umfangreich.
wenn ich da was per mail oder so durchschicken könnte wäre besser?
du kannst mich gerne kontaktieren unter der angegebenen email-adresse
-- Table structure for table `fund_companies`
CREATE TABLE `fund_companies` (
`company_id` varchar(8) collate utf8_unicode_ci NOT NULL default '0',
`fund_company_alias_name_id` varchar(8) collate utf8_unicode_ci NOT NULL,
`activated` enum('Y','N') collate utf8_unicode_ci NOT NULL default 'N',
`logo_url` varchar(255) collate utf8_unicode_ci default NULL,
PRIMARY KEY (`company_id`),
KEY `fund_company_alias_name_id` (`fund_company_alias_name_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `fund_companies_alias_names`
CREATE TABLE `fund_companies_alias_names` (
`company_id` varchar(8) collate utf8_unicode_ci NOT NULL,
`fund_company_alias_name_id` varchar(8) collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`fund_company_alias_name_id`),
KEY `company_id` (`company_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `fund_company_alias_name`
CREATE TABLE `fund_company_alias_name` (
`fund_company_alias_name_id` varchar(8) collate utf8_unicode_ci NOT NULL,
`fund_company_alias_name` varchar(255) collate utf8_unicode_ci NOT NULL,
`sql_timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
`parent_fund_company_alias_name_id` varchar(8) collate utf8_unicode_ci default NULL,
PRIMARY KEY (`fund_company_alias_name_id`),
KEY `parent_fund_company_alias_name_id` (`parent_fund_company_alias_name_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `fund_company_extending_options_availability`
CREATE TABLE `fund_company_extending_options_availability` (
`option_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
`isin` varchar(12) collate utf8_unicode_ci NOT NULL default '',
`company_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
PRIMARY KEY (`option_id`,`isin`,`company_id`),
KEY `isin` (`isin`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `fund_extending_options`
CREATE TABLE `fund_extending_options` (
`option_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
`name` varchar(255) collate utf8_unicode_ci default NULL,
PRIMARY KEY (`option_id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `fund_extending_options_availability`
CREATE TABLE `fund_extending_options_availability` (
`option_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
`isin` varchar(12) collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`option_id`,`isin`),
KEY `isin` (`isin`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `fund_platform_extending_options_availability`
CREATE TABLE `fund_platform_extending_options_availability` (
`option_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
`isin` varchar(12) collate utf8_unicode_ci NOT NULL,
`platform_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
PRIMARY KEY (`option_id`,`isin`,`platform_id`),
KEY `isin` (`isin`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `fund_platform_fund_availability`
CREATE TABLE `fund_platform_fund_availability` (
`platform_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
`isin` varchar(12) collate utf8_unicode_ci NOT NULL default '',
`discount` float(5,2) unsigned default NULL,
`discount_savings_plan` float(5,2) unsigned default NULL,
`min_investment_sum_savings_plan` float(12,2) unsigned default NULL,
`min_investment_sum_savings_plan_currency` varchar(32) collate utf8_unicode_ci default NULL,
`min_investment_sum_onetime` float(12,2) unsigned default NULL,
`min_investment_sum_onetime_currency` varchar(32) collate utf8_unicode_ci default NULL,
`savings_plan_capable` enum('Y','N') collate utf8_unicode_ci default NULL,
PRIMARY KEY (`platform_id`,`isin`),
KEY `isin` (`isin`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `fund_platform_fund_company_availability`
CREATE TABLE `fund_platform_fund_company_availability` (
`platform_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
`company_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
PRIMARY KEY (`platform_id`,`company_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `fund_platforms`
CREATE TABLE `fund_platforms` (
`platform_id` varchar(8) collate utf8_unicode_ci NOT NULL default '',
`name` varchar(255) collate utf8_unicode_ci NOT NULL default '0',
`abbreviation` varchar(255) collate utf8_unicode_ci default NULL,
`logo_url` varchar(255) collate utf8_unicode_ci default NULL,
`platform_type` enum('platform','directbank') collate utf8_unicode_ci NOT NULL default 'platform',
`img_logo_small` varchar(255) collate utf8_unicode_ci NOT NULL default '',
PRIMARY KEY (`platform_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- Table structure for table `funds`
CREATE TABLE `funds` (
`isin` varchar(12) collate utf8_unicode_ci NOT NULL,
`name` varchar(255) collate utf8_unicode_ci default NULL,
`wkn` varchar(6) collate utf8_unicode_ci default NULL,
`fund_load` float(5,2) unsigned default NULL,
`company_id` varchar(8) collate utf8_unicode_ci default NULL,
PRIMARY KEY (`isin`),
KEY `isin` (`isin`),
KEY `wkn` (`wkn`),
KEY `company_id` (`company_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Ilja
yo,
erklär doch bitte mal genauer, wie genau du auf diesen schluß kommst.
die begründung liegt letzlich in der gruppierung. dort werden spalten mit gleichen inhalt zusammengefaßt (gruppiert). so können zum beispiel 5 datensätze alle den gleichen spalteninhalt in der gruppierung haben, und werden somit zusammengefasst, sprich aus 5 datensätzen wird einer als ergebnis zurück gegeben. wenn du nun noch andere als die gruppierungs-spalten mit ausgeben willst, dann können diese werte (in gegensatz zu den gruppiernugs-spalten) sich in den 5 datensätzen unterscheiden. da er aber nur datensatz zurück gibt, weiß das dbms nicht, welchen der unterscheidlichen werte es nun nehmen soll. deswegen gibt es eine regel, die andere dbms auch richtig umsetzen und fehlermeldungen schmeissen, dass du nur spaletn ausgeben kannst, über die due auch gruppierst hast oder die eben bestandteil einer aggregat-funktion wie zum beispiel SUM() sind.
das das datenbank-design schlecht ist weiss ich, das habe ich vor jahren ohne großes grundwissen entworfen gehabt und soll dummerweise heute noch herhalten.
fragt sich, was mehr mühe macht, es mal zu ändern oder beizubehalten. irgendwann muss man sich vom alten dingen trennen können. leider hat man nicht immer diese entscheidung in der hand.
die tabellendefinitionen habe ich mal untenstehend reinkopiert.
was die daten angeht, wäre das hier zu umfangreich.
viel wichtiger als die "nackten" ddl befehle anzugeben wäre es, zu erklären, was du machen willst, welche tabellen davon betroffen sind und beispieldaten anzugeben. damit meine ich nicht alle daten, sondern eben nur ein paar beispiel, was vorhanden ist nud was dabei rauskommen soll.
Ilja
yo,
erklär doch bitte mal genauer, wie genau du auf diesen schluß kommst.
die begründung liegt letzlich in der gruppierung. dort werden spalten mit gleichen inhalt zusammengefaßt (gruppiert). so können zum beispiel 5 datensätze alle den gleichen spalteninhalt in der gruppierung haben, und werden somit zusammengefasst, sprich aus 5 datensätzen wird einer als ergebnis zurück gegeben. wenn du nun noch andere als die gruppierungs-spalten mit ausgeben willst, dann können diese werte (in gegensatz zu den gruppiernugs-spalten) sich in den 5 datensätzen unterscheiden. da er aber nur datensatz zurück gibt, weiß das dbms nicht, welchen der unterscheidlichen werte es nun nehmen soll. deswegen gibt es eine regel, die andere dbms auch richtig umsetzen und fehlermeldungen schmeissen, dass du nur spaletn ausgeben kannst, über die due auch gruppierst hast oder die eben bestandteil einer aggregat-funktion wie zum beispiel SUM() sind.
so wie access beispielsweise... - heisst, ich sollte möglichst jeder abzufragenden spalte eine aggregatsfunktion zuweisen. wobei es doch egal sein sollte, wenn bei einer spalte ohnehin ein eindeutiger wert rauskommt?
das das datenbank-design schlecht ist weiss ich, das habe ich vor jahren ohne großes grundwissen entworfen gehabt und soll dummerweise heute noch herhalten.
fragt sich, was mehr mühe macht, es mal zu ändern oder beizubehalten. irgendwann muss man sich vom alten dingen trennen können. leider hat man nicht immer diese entscheidung in der hand.
so ist es. es ist derzeit nicht möglich.
die tabellendefinitionen habe ich mal untenstehend reinkopiert.
was die daten angeht, wäre das hier zu umfangreich.viel wichtiger als die "nackten" ddl befehle anzugeben wäre es, zu erklären, was du machen willst, welche tabellen davon betroffen sind und beispieldaten anzugeben. damit meine ich nicht alle daten, sondern eben nur ein paar beispiel, was vorhanden ist nud was dabei rauskommen soll.
ich hatte mal angefangen, nur einen datensat zusammenzuklamüsern. allein einer ist schon zu umfangreich für einen thread hier, und allein das manuelle zusammenstellen ist schon viel zu aufwendig.
am einfachsten wäre es, ich schicke dir zu tabellendefinitionen 2,3 beispieldatensätze. das wäre ja auch zum austesten das einfachste.
wobei ich sagen muss dass es mit einem test mit 'count(distinct spalte a, spalte b)' ganz gut aussieht, was das zählen der datensätze angeht.
natürlich könnte ich evtl. die geschwindigkeit der abfrage mit dem vorschlag, aggregatsfunktionen entsprechend einzusetzen evtl. erhöhen.
das müsste ich testen.
danke u. gruß