Získání dat přes více tabulek s podmínkou ve vazbě

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
AuHau
Člen | 13
+
0
-

Ahojte!
Musím předeslat, že jsem úplný začátečník jak s Nette, tak s Nette Database a jako člověk, který doteďka psal SQL dotazy, je to pro mě docela šok, každopádně i po několika týdnech zápasení mám pořád vůli a chuť tomu přijít na kloub.
Do teď se mi dařilo najít odpověď na moje otázky hledáním zde na foru, bohužel teď jsem v koncích a už si nevím rady, tak bych vás chtěl poprosit o pomoc.

Mám 3 tabulky – t_companies, t_contact_persons, t_reports

CREATE TABLE t_companies
(
  sys_uid integer NOT NULL,
  sys_date timestamp without time zone NOT NULL DEFAULT now(),
  cid serial NOT NULL,
  name character varying NOT NULL,
  url character varying,
  description text,
  address character varying,
  active boolean NOT NULL DEFAULT true,
  oid integer,
  CONSTRAINT t_companies_pkey PRIMARY KEY (cid),
  CONSTRAINT t_companies_oid_fkey FOREIGN KEY (oid)
      REFERENCES t_orgs (oid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT t_companies_sys_uid_fkey FOREIGN KEY (sys_uid)
      REFERENCES t_users (uid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

CREATE TABLE t_contact_persons
(
  sys_uid integer NOT NULL,
  sys_date timestamp without time zone NOT NULL DEFAULT now(),
  id_person serial NOT NULL,
  cid integer NOT NULL,
  name character varying NOT NULL,
  surname character varying NOT NULL,
  title character varying,
  email character varying,
  mobile_phone character varying,
  telephone character varying,
  division character varying,
  CONSTRAINT t_contact_persons_pkey PRIMARY KEY (id_person),
  CONSTRAINT t_contact_persons_cid_fkey FOREIGN KEY (cid)
      REFERENCES t_companies (cid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT t_contact_persons_sys_uid_fkey FOREIGN KEY (sys_uid)
      REFERENCES t_users (uid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE RESTRICT
)

CREATE TABLE t_reports
(
  id_contact serial NOT NULL,
  uid integer NOT NULL,
  id_person integer NOT NULL,
  eid integer,
  id_state integer NOT NULL DEFAULT 0,
  date timestamp without time zone NOT NULL,
  content text,
  summary character varying NOT NULL,
  motivation character varying,
  CONSTRAINT t_reports_pkey PRIMARY KEY (id_contact),
  CONSTRAINT t_reports_eid_fkey FOREIGN KEY (eid)
      REFERENCES t_events (eid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT t_reports_id_person_fkey FOREIGN KEY (id_person)
      REFERENCES t_contact_persons (id_person) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT t_reports_id_state_fkey FOREIGN KEY (id_state)
      REFERENCES c_state (id_state) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT t_reports_uid_fkey FOREIGN KEY (uid)
      REFERENCES t_users (uid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION

A vypisuju všechny firmy a u každý chci vypsat status posledního reportu, který bude mít status nenulový, tedy v SQL něco takovéhoto:

SELECT
	*,
	(
		SELECT rp.status
		FROM t_contact_persons cp
			LEFT JOIN t_reports rp USING (id_person)
		WHERE cp.cid = t_companies.cid
			AND rp.status > 0
		ORDER BY rp.date DESC
		LIMIT 1
	) AS last_contact
FROM t_companies

Zkoušel jsem za sebe dát 2 krát related, ale to jsem okamžitě zjistil, že je blbost.

Používám Nette 2.1 RC4, a Postgres.

Můžete prosím poradit?
Předem mockrát děkuji

Editoval AuHau (25. 12. 2013 0:36)

Stic
Člen | 28
+
0
-

tiez by som potreboval nejako poriesit query v ktorom je nieco taketo:

LEFT JOIN `accepted_task`ON `task`.`id` = `accepted_task`.`task_id` AND (`accepted_task`.`status` NOT IN (4))

Ked sa to poriesi cez ->query(), tak ako pise kolega hore, tak potom samozrejme nefunguje ->related() a podobne, lebo query vracia ResultSet a nie Table\Selection.

Da sa nejako rucne vygenerovat JOIN okrem query?

Editoval Stic (25. 12. 2013 18:08)

AuHau
Člen | 13
+
0
-

Hmm, tak jsem to trochu vyřešil přidáním sloupcem cid (Company ID) do t_reports, teď se tedy můžu dostat přímo k těm reportům a můžu vynechat tu prostřední tabulku t_contacts_persons.
Trochu se mi to nelíbí, jelikož mi to přijde jako redundance, ale co…

Každopádně jsem teď narazil na další problém, který asi vychází z nepochopení ActiveRow.

Chci se dostat ke jménu statusu, který je v enum tabulce. K id_status se mi podařilo dostat celkem bez problému, ale nevim jak ho přeložit za normální čitelný jméno, který mám uložený v c_status.

Koukal, jsem že metoda fetch() vrací ActiveRow, ve kterém by mělo jít přece použít metodu ref(), ne? Chtěl jsem tedy použít v šabloně takovýto zápis:

{$company->related('t_reports')->where('id_state>0')->order('date DESC')->limit(1)->fetch()->ref('id_state')->name}

To avšak zkolabuje na erroru Trying to get property of non-object.
Tak po chvilce hraní jsem tedy dospěl k sice funkčnímu, ale pěkně ošklivému řešení:

{var $report =  $company->related('t_reports')->where('id_state>0')->order('date DESC')->fetch()}
{$presenter->db->table('c_state')->get($report['id_state'])['name']}

Při snaze překonat tento problém jsem jen tak zkusil to dát do foreach (ikdyž to postrádá smysl) a ono to funguje… Proč? Trochu to nepobírám :(

{foreach  $company->related('t_reports')->where('id_state>0')->order('date DESC')->limit(1) as $state}
        {$state->ref('id_state')->name}
{/foreach}

Nemohli by jste mě prosím trochu nakopnout správný směrem?

Editoval AuHau (25. 12. 2013 20:56)