[C++][Bazy danych] Wypis bazy danych na podstawie tablicy

Stefaniak1916
Użytkownik
Użytkownik
Posty: 55
Rejestracja: 11 lut 2017, o 18:10
Płeć: Mężczyzna
Lokalizacja: Warszawa
Podziękował: 13 razy

[C++][Bazy danych] Wypis bazy danych na podstawie tablicy

Post autor: Stefaniak1916 »

Hej, robię w c++ program bazy danych i zrobiłem funkcję, która wypisuje posortowane alfabetycznie imiona z tablicy. Jednak chcę, żeby program nie tylko wypisywał imiona ale też inne dane danego imiennika - nazwisko, miasto, datę urodzin. Problem pojawia się, gdy imiona się powtarzają, wtedy następuje kilkakrotny wypis danych danego imiennika.
Wiem, że problem to wina użycia tych dwóch forów, jednak nie mogę wymyślić innego rozwiązania. Nie jestem zaawansowanym programistą, więc proszę o jak najprostsze wskazówki, rozwiązania.

Kod: Zaznacz cały

Nazwiska[k]//tablica z posortowanymi alfabetycznie nazwiskami
for (int k = 0; k < size; k++)
    {
        for (int j = 0; j < size; j++)
        {
            if (Nazwiska[k]==dane[j].imie)
            {
                cout<<endl;
                cout <<"Miejsce nr "<<j+1<<endl;
                cout <<"Imie: "<<dane[j].imie<<endl;
                cout <<"Nazwisko: "<<dane[j].nazwisko<<endl;
                cout <<"Miasto: "<<dane[j].miasto<<endl;
                cout <<"Data urodzenia: "<<dane[j].dzien<<"."<<dane[j].miesiac<<"."<<dane[j].rok<<endl;
            }
        }
    }
Ponury123
Użytkownik
Użytkownik
Posty: 128
Rejestracja: 5 lip 2015, o 14:48
Płeć: Mężczyzna
Lokalizacja: nie wiem
Podziękował: 11 razy
Pomógł: 24 razy

Re: [C++][Bazy danych] Wypis bazy danych na podstawie tablic

Post autor: Ponury123 »

Takie sortowanie najpierw po nazwisku(zmiennej z obiektu) i potem porównywanie nigdy nie jest dobrym pomysłem, lepiej napisać Comparator do porównywania dwóch obiektów/struktur. Kod poniżej.

Btw. nie wiem jak pozyskujesz te dane z bazy danych, ale jeśli jest to jakaś realna baza w SQL-u to wystarczy odpowiednie zapytanie SQL, nie bójmy się wykorzystywać potęgi SQL-a

Kod: Zaznacz cały

#include <iostream>
#include <list>
#include <string>
#include <algorithm>

struct User
{
	int id;
	std::string name, surname, city;

	User(int userId, std::string userName, std::string userSurname, std::string userCity) :
		id(userId), name(userName), surname(userSurname), city(userCity){}

	bool operator <(const User & userObj) const
	{
		return id < userObj.id;
	}
};


struct Comparator
{
	// Compare 2 User using surname
	bool operator ()(const User & user1, const User & user2)
	{
		if (user1.surname == user2.surname)
			return user1 < user2;
		return user1.surname < user2.surname;

	}
};

int main(int argc, char** argv)
{

	std::list<User> list = { User(1, "Piotrek", "D", "Wro"),
		User(2, "Piotrek", "C", "Wro"),
		User(3, "Piotrek", "E", "Wro"),
		User(4, "Marcin", "A", "Wro"),
		User(5, "Michal", "B", "Wro") };

	list.sort(Comparator());

	for (User & user : list)
		std::cout << user.id << "  " << user.name << "   "<< user.surname << std::endl;

	return 0;
}
Dudenzz
Użytkownik
Użytkownik
Posty: 93
Rejestracja: 8 mar 2009, o 18:21
Płeć: Mężczyzna
Pomógł: 19 razy

Re: [C++][Bazy danych] Wypis bazy danych na podstawie tablic

Post autor: Dudenzz »

Praktyczna uwaga - nie powinieneś nazywać tablicy imion jako "Nazwiska". Poprawną nazwą jest "imiona". Mała/Wielka litera jest w nazwach również istotnym aspektem. W konwencji C/C++ zmienne powinny rozpoczynać się małą literą. Duża litera zarezerwowana jest dla nazw klas, struktur, typów numerowanych, etc. Dobrze, że nazwy zmiennych opisują to co reprezentują. Użycie znanych skrótów (w tym przykładzie "j". "k" jako zmienne iterowane) jest również dobrą praktyką. Więcej szczegółów znajdziesz np. tutaj

Kod: Zaznacz cały

https://google.github.io/styleguide/cppguide.html#Naming
. Dodatkowo - nie jest to pisana reguła, ale - zwykle pisząc w C++ posługujemy się nazwami angielskimi. Jeżeli nie znasz dobrze tego języka, pozostań przy polskich nazwach, ale miej na uwadze to, że duża część zasobów z którymi się spotkasz przy nauce programowania będzie po angielsku.

Co do problemu zasadniczego.

W bazach danych istnieje pojęcie atrybutu kluczowego, od którego zależą wszystkie pozostałe atrybuty w relacji (tabeli). Oznacza to, że na podstawie atrybutu kluczowego jesteś w stanie określić wartość wszystkich innych parametrów. Takim atrybutem może być na przykład numer PESEL. Jeden pesel przypisany jest do jednego człowieka i wszystkich związanych z nim atrybutów. Na podstawie PESELu możemy podać jego imię, nazwisko, datę urodzenia, numer buta... w Twojej bazie danych takiego atrybutu prawdopodobnie nie ma.

W praktyce, projektując bazę danych, nie wykorzystujemy atrybutów mających swoje odzwierciedlenie w rzeczywistości. Dużo wygodniej jest użyć atrybutu "sztucznego", np. "identyfikator". Jeżeli chcesz, żeby twoja baza danych przypominała prawdziwe, relacyjne bazy danych, to taki atrybut powinien być jednym z pól klasy reprezentującej jedną osobę.

Z drugiej strony obiekt, jest samodzielną instancją reprezentującą wszystkie cechy tego obiektu. W związku z tym można go wykorzystać jako identyfikator danej osoby.
Zatem rozwiązania Twojego problemu są trzy. Powyżej zostały opisane dwa pierwsze. Trzecie to rozwiązanie, które doraźnie rozwiązuje Twój problem nie wprowadzając pojęcia identyfikatora.

Rozwiązanie pierwsze: sortowanie według nie zwraca tablicy nazwisk, a tablicę identyfikatorów,
Rozwiązanie drugie: sortowanie według nazwisk nie zwraca tablicy nazwisk, a tablicę obiektów (to rozwiązanie zostało zaproponowane powyżej, z tym że, zamiast tablicy wykorzystywana jest stl'owa lista),
Rozwiązanie trzecie: w linii 14 ("wewnątrz ifa") Twojego kodu wpisz linijkę o treći

Kod: Zaznacz cały

break;
.

Zobaczysz wtedy dlaczego użycie imienia jako identyfikatora jest złym pomysłem.
ODPOWIEDZ