Neues Projekt (Schnäppchenjäger)

Kampfgummibaerlie

Datenbank-Guru
Beiträge
731
Soda, ich habe mir bisher einen günstigen Ubuntu-Root-Server gefunden, damit ich mir keine großen Sorgen wegen der Unterstützung vom OS zwecks Installation von PgSQL und Co am NAS machen muss, noch dazu bietet dieser Server auch eine deutlich bessere Übertragungsrate.

Nach langem herumkauern, aber schon öfters der Überlegung, dass ich wöchentlich die üblichen Prospekte durchschaue, und alles was darinsteht einfach in eine Datenbank einlese, und dann "ausspucke" was diese Woche die Top-Angebote sind.

Der Name "Schnäppchenjäger" erscheint mir als sinnvoll, weil ich auch schon Ideen bezüglich der Landing-Page habe...
Aber, um mal zu SQL zu gehen:
Ich benötige:
1.: Eine Tabelle Hersteller(id, name)
2.: Eine Tabelle Produktgruppen(id, name)
3.: Eine Tabelle Produkte(id, hersteller, produktgruppe, name)
4.: Eine Tabelle Kioske(id, name)
5.: Eine Tabelle Angebote(kiosk, produkt, preis, stück(default 1))
6.: Eine Tabelle Vergünstigungen(kiosk, produkt, rabatt, minkaufmenge)
7.: Eine Ansicht, welche die Tabellen 5 und 6 vereinigt, und nach möglichkeit das günstigste diese Woche am Markt ausgibt.

Wola, klingt ganz einfach, wenn ich es so aufschreibe xD

Würde aber gerne noch um eure Kritik bitten ;)
Mögliche Denkfehler, unnötig komplizierten Aufbau, oder sonst etwas also... *mir schonmal eine Schaufel hol, damit ich mich vor scharm eingraben kann* :D

Danke euch ;)
EDIT: nachdem ich auf den Homepages keine privaten Dinge abspeichern werde, hier ein Link zu all meinen im Kopf stehenden Projekten...
Umsetzung ist dann was anderes xD
 
Werbung:
erste lücke bemerkt, beim schreiben ;)
bei der Tabelle vergünstigungen (punkt 6) keine daterange gehabt, jetzt schon ;)

hier mal meine bisherige Datenbank:
Code:
create table hersteller(id serial primary key, name text unique not null);
create table produktgruppen(id serial primary key, name text unique not null);
create table produkte(id serial primary key, hersteller integer references hersteller(id), produktgruppe integer references produktgruppen(id), name text not null, unique(hersteller, name));
create table kioske(id serial primary key, name text unique not null);
create table angebote(kiosk integer references kioske(id), produkt integer references produkte(id), preis numeric check(preis >= 0) not null, stück integer default 1 check(stück >= 1));
create table vergünstigungen(kiosk integer references kioske(id), produkt integer references produkte(id), rabatt numeric check(rabatt >= '0') default '0', mindestkaufmenge integer check(mindestkaufmenge >= 1) not null,zeitrahmen daterange default daterange(now()::date, (now()::date+'7 days'::interval)::date));
 
Müsste angebote nicht auch einen Zeitraum haben, in dem es gültig ist?

Ich würde ja Spaltennamen (und Tabellennamen) mit Umlauten vermeiden. Langfristig macht das echt eklige Probleme.

Mit modernen Postgres Versionen sollte man serial nicht mehr verwenden. generated by default as identity ist besser. Ich persönlich nehme immer generated always as identity damit man sofort einen Fehler bekommt wenn man versucht die Sequence zu umgehen.
 
@castorp

Danke für die konstruktive Kritik deinerseits ;)
Kenne mich mit diesem generated always as identity noch nicht wirklich aus...
Werde erst einmal googeln, bei Problemen mache ich einen neuen Thread auf =D

werde die bisher erstellte Datenbank nach Umlauten durchsuchen und diese ausmerzen.
Ich habe in der Tabelle "Angebote" eig. die Artikel aufgelistet, die immer angeboten werden, auch ohne einer speziellen Aktion oder ähnlichem.

in wiefern ist das generated by default as identity besser? Vielleicht ein paar kluge Worte von unserem mr. Elephant? ;)
 
Ich denke ein "Status" fehlt.
Ansonsten bist du immer gezwungen Daten sofort zu löschen bzw. zeitgerecht einzustellen. Wenn du löschen musst verlierst du damit die Historie in der Datenbank.
Mit einem Status kannst du Daten vorbereiten und dann mit dem richtigen Status bereitstellen.
"Name" ist in vielen Programmen ein Schlüsselwort - würde Bezeichnung oder sowas nehmen.
Da ich nicht weiß ob da nicht auch was in anderen Mengeneinheiten wie Stück angeboten wird frage ich mich ob a) keine Mengeneinheit notwendig ist und b) falls ja ob die Mindestkaufmenge dann wirklich 1?
 
Außerdem würde ich mir überlegen die Felder in den Tabellen eindeutig zu benennen. Bei deiner Abfrage kommt sonst x-mal das ominöse Feld "Name" vor. Und auch immer wieder ID.
Bin ein Freund eindeutiger Feldnamen, erleichtert das Leben imho später ungemein.
 
in wiefern ist das generated by default as identity besser?

Weil es einerseits dem SQL Standard entspricht. Zusätzlich ist es einfacher Privilegien auf die Tabelle zu vergeben. Wenn Du mit einem serial das INSERT Privileg für die Tabelle vergibst, musst Du zusätzlich noch das SELECT Privileg für die Sequence vergeben.
Bei einer Identity Spalte macht das Postgres automatisch (und auch das zurücknehmen der Privilegien).

Hier wird das auch nochmal ein bisschen ausführlicher erklärt.

Wie gesagt: ich finde generated ALWAYS as identity besser, da man dann nicht zufällig einen Wert "an der Datenbank vorbei" einfügen kann.
 
Wie gesagt: ich finde generated ALWAYS as identity besser, da man dann nicht zufällig einen Wert "an der Datenbank vorbei" einfügen kann.

Meinst du damit das automatische hochzählen, falls man beim insert einen Error hat? sprich er zählt den integer weiter, kann ihn aber wegen des errors nicht einfügen, und danach ist die nächste id um 2 höher?

stimmt, das hätte ich gerne los, habe aber bisher einfach damit gelebt xD

meine View sieht jetzt so aus, ich bin damit zufrieden!
Code:
 SELECT angebote.produkt AS angebot,
    vertriebsfirmen.name,
    angebote.preis,
    '0%'::text AS "?column?",
    angebote.preis AS gesamtpreis,
    1 AS minkaufstk
   FROM angebote
     JOIN vertriebsfirmen ON vertriebsfirmen.id = angebote.vertriebsfirma
UNION
 SELECT aktionen.produkt AS angebot,
    vertriebsfirmen.name,
    angebote.preis * (100::numeric - aktionen.nachlass) / 100::numeric AS preis,
    aktionen.nachlass || '%'::text,
    angebote.preis * (100::numeric - aktionen.nachlass) / 100::numeric * aktionen.minkaufstk::numeric AS gesamtpreis,
    aktionen.minkaufstk
   FROM aktionen
     JOIN vertriebsfirmen ON aktionen.firma = vertriebsfirmen.id
     JOIN angebote ON angebote.vertriebsfirma = vertriebsfirmen.id;

Resultat:
Code:
angebot, filiale, preis, vergünstigung, gesamtpreis, mindestkaufstück
1    "Hofer"    0.725    "50%"    2.90000000000000000000    4
1    "Hofer"    1.45    "0%"    1.45    1
In meinem Fall habe ich nur den Vergleich zwischen 1 Joghurt oder 4 Joghurts kaufen... wenn man 4 Joghurts kauft, zahlt man 2... (4 zum preis von 2)

Warum habe ich die Mindestkaufstück auf default 1?
falls ich irgendwann soweit bin, und bereits alle produkte in die Datenbank habe, dass es einfacher ist, weil man kauft ja (normalerweise) immer nur 1 produkt....

Danke für eure Hilfe bisher ;)
 
Meinst du damit das automatische hochzählen, falls man beim insert einen Error hat? sprich er zählt den integer weiter, kann ihn aber wegen des errors nicht einfügen, und danach ist die nächste id um 2 höher?
Nein genau anders rum :)

Code:
create table problem
(
  id integer generated by default as identity primary key,
  some_text text
);

insert into problem (id, some_text) values (1, 'one');
insert into problem (some_text) values ('two');
 
Zuerstmal:
Schöne Projektidee!

Das mit den Kiosken habe ich nicht verstanden. Geht es um Ladenlokale, Standorte, Verkaufsstellen?
Vielleicht gehört hier eine Möglichkeit dazu, auch (reine) online Verkaufsplätze anzugeben.
Nehmen wir mal ebay als Beispiel, private und kommerzielle Anbieter sind da gemischt. Die kommerziellen können Ketten oder große Händler sein, z.B. Saturn, und das dann noch im Einzelfall ein spezieller Saturn in einer bestimmten Stadt.
Sowas muss man natürlich nicht alles von Anfang an abbilden, aber vielleicht im Datenmodell "vorhersehen" bzw. vorbereiten.

Die Unterscheidung von Angeboten und Aktionen durch separate Tabellen scheint mir suboptimal. Lieber alle Produkte in eine Tabelle. Dann die unterschiedlichen Darreichungsformen, Verpackungsgrößen, Mindestabnahme Menge usw. in einer separaten Tabelle, inkl. Zeitraum und mglw anderer "Randbedingungen", wie auch MDaniel angemerkt hat.
Das Produkt ist generell z.B. Milka Vollmilch. Gibt es als Standardtafel,als Osterhase, als Weihnachtsmann und in der Collection .. .
Es gibt ja seit einigen Jahren keine Regularien mehr für Standardverpackungsgrößen. Die Tafel Schokolade hat also nicht zwangsläufig 100gr, usw. usw. interessant ist bei Lebensmitteln und vielem anderenen unabhängig von der Verpackung immer der Kilopreis.

Was zu fehlen scheint sind irgendwelche Formen von Rabatten, Gutscheincodes usw.
 
Vielleicht habe ich es schlecht erklärt im post #0...

Ich möchte mir jede Woche die neuen Prospekte durchblättern, in die Tabelle eintragen, und dann von dieser wiederum den Markt suchen, wo das Ganze am günstigsten ist, oder auch, damit ich einen überblick habe, "was ist diese Woche günstig", sprich ich rede hier von "Hofer", in Deutschland Aldi oder so, Spar, Billa, Billa Plus, und was weiß ich was alles...

Nachdem der Billa das selbe Römerquelle Mineralwasser verkaufen wird, wie andere solche Märkte, möchte ich herausfilter, bei welchem ich günstiger/am günstigsten aussteige.

Das mit Märkten ist nur eine Idee meinerseits, die eher futuristisch ist. Ich möchte irgendwann, falls die Datenbank anwächst sogar noch mit Fahrzeugen verknüpfen, sprich "BMW 120i Cabrio" => Verbrauch im @ 8 Liter/100km und daraus erfassen, ob es günstiger kommt, wenn ich bis zum nächsten, günstigeren Markt fahre, oder zum näher liegenden.

Also, einen Beispielfall:
es ist Donnerstag, der neue Kurier kommt per Post bei mir an, ich durchstöbere alle Reklamen, trage die Angebote/Vergünstigungen in die Datenbank ein, und schaue am Ende, was wie wo wann und so weiter mir am Ende ein paar Cent spart. (wer den Penny nicht ehrt, ist die Krone nicht wert, oder so)...

deshalb trage ich zB "Coca Cola" als Herstellerfirma ein, und auch als Produkt (herstellerfirma Coca Cola, Produkt Coca Cola), damit ich dann bei der Tabelle "Angebote" das Produkt 3x drinnen stehen habe, weil 3 verschiedene Märkte das Coca Cola verkaufen, und ich herausfiltern möchte, wo es am günstigsten ist.

herstellerfirmen sind eben die verschiedenen hersteller, Eistee gibt es von Nestea, von Rauch und ich habe keine Ahnung von wem aller...
 
Werbung:
Habe die Datenbank sowie Homepage deutlich überarbeitet...

Arbeite jetzt mit simplen 4 Tabellen (angebote, marken, produkte, shops)

das mit Vergünstigungen fehlt noch, sollte aber nicht das Problem darstellen ;)


auf der Datenbank wird eig. nur simpel angezeigt, wo es was um welchen preis gibt, aber auch Rom wurde nicht an einem Tag erbaut xD

EDIT: Auch die Homepage deutlich vereinfacht... ist jetzt nurnoch eine Seite, auf der das eigentliche Ziel vorhanden ist.
Die Administration kann ich ja auch anders lösen...

(hatte ein Sicherheitsproblem denke ich, deshalb auch von vorne anfangen müssen)
Problembeschreibung:
der postgres-user war heute kein SU mehr, und ein neuer user wurde hinzugefügt und zum SU gemacht...

Mal schauen, was morgen so passiert...
 
Zurück
Oben