Save filter criteria on a SQL database - sql

I have a Products table as follows:
create table dbo.Product (
Id int not null
Name nvarchar (80) not null,
Price decimal not null
)
I am creating Baskets (lists of products) as follows:
create table dbo.Baskets (
Id int not null
Name nvarchar (80) not null
)
create table dbo.BasketProducts (
BasketId int not null,
ProductId int not null,
)
A basket is created based on a Search Criteria using parameters:
MinimumPrice;
MaximumPrice;
Categories (can be zero to many);
MinimumWarrantyPeriod
I need to save these parameters so later I know how the basket was created.
In the future I will have more parameters so I see 2 options:
Add MinimumPrice, MaximumPrice and MinimumWarrantyPeriod as columns to Basket table and add a BasketCategories and Categories tables to relate a Basket to Categories.
Create a more flexible design using a Parameters table:
create table dbo.BasketParameters (
BasketId int not null,
ParameterTypeId int not null,
Value nvarchar (400) not null
)
create table dbo.ParameterType (
Id int not null
Name nvarchar (80) not null
)
Parameter types are MinimumPrice, MaximumPrice, Categories, MinimumWarrantyPeriod, etc.
So for each Basket I have a list of BasketParameters, all different, having each on value. Later if I need for parameter types I add them to the ParameterType table ...
The application will be responsible for using each Basket Parameters to build the Basket ... I will have, for example, a Categories table but will be decoupled from the BasketParameters.
Does this make sense? Which approach would you use?

Your first option is superior (especially since you are using a relational data store. I.e. SQL Server), since it is properly referential. This will be much easier to maintain and query as well as far more performant.
Your second solution is equivalent to an EVA table: https://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model
Which are usually a terrible idea (and if you need that type of flexibility you should probably use a Document Database or other NoSQL Solution instead). The only benefit to this is if you need to add/remove attributes regularly or based on other criteria.

Related

SQL Table with mixed data type field Best Practice

everyone,
I would like an advice on best practice for creating realtional database structure with field having mixed data type.
I have 'datasets' (some business objects) and I would like to have list of parameters, associated with each dataset. And those parameters can have different types - strings, integers, float and json values.
What would be the best structure for the parameters table? Should I have single column with string type?
CREATE TABLE param_desc (
id serial PRIMARY KEY,
name varchar NOT NULL,
param_type int -- varchar, int, real, json
);
CREATE TABLE param_value (
id serial PRIMARY KEY,
dataset_id int NOT NULL,
param int NOT NULL REFERENCES param_desc (id),
value varchar NOT NULL,
CONSTRAINT _param_object_id_param_name_id_time_from_key UNIQUE (dataset_id, param)
);
The problem with such approach is that I can't easily cast value for some additional conditions. For example, I want to get all datasets with some specific integer parameter, having int value more than 10. But if I write where clause, the casting will return error, as other non-integer parameters can't be casted.
SELECT dataset_id FROM vw_param_current WHERE name = 'priority' AND value::int > 5
Or should I have 4 separate columns, with 3 of them being NULL for every row?
Or should I have 4 different tables?

List of lists in SQL

CREATE TABLE Persons(
ID int not null,
Name varchar(255) not null,
Description varchar(255));
INSERT INTO Persons values(15, "Alex", [["cool",1,19],["strong", 1, 20]]);
Is it possible to use a list of lists in this case or should I use another type?
Consider how you will query this data in the future. For example, will you need to search for a person with a specific trait in their description? How would you write that query if it's stored in a "list" as you call it? Using any kind of semi-structured data makes it easy to put data in, but it's not always clear how to search the data afterwards. You should think ahead with this in mind.
If you use the technique of structuring your database into Normal Forms, you will end up with a database that is the most flexible in terms of supporting a wide variety of queries.
Any standard Relational DMBS is not supposed to store such data as it violates normalisation principles.
While the following schema will suffice to create a table it saves a little time now and creates massive time sink later.
CREATE TABLE Persons
(
ID int not null,
Name varchar(255) not null,
MultiValueColumnViolates1NF varchar(255)
)
;
It violates the 1st NF because column MultiValueColumnViolates1NF allows multiple data tuples in a single cell. Yes, it can hold a list (JSON or XML depends on the RDBMS flavour). Or as normal DBAs call this: Garbage in, garbage out. Or as I call it: Excel tables.
An actual design to store such data preferably is at least in 2NF. Which in this case can be:
CREATE TABLE People
(
Name varchar(255) not null,
SingleValueColumn varchar(255)
)
;
The INSERT statement will then allow inserting data like:
INSERT INTO People
VALUES
( 'Alex', '["cool",1,19]' ),
( 'Alex', '["strong", 1, 20]')
;
One issue: No unique key possible. So there are multiple rows coming back if data is retrieved for 'Alex'.
Probably not what you want to achieve.
An RDMBS performant way to store this data is in two separate tables.
CREATE TABLE People
(
ID int not null,
Name varchar(255) not null
)
;
CREATE TABLE People_Data
(
ID_People int NOT NULL,
Key varchar(100) NOT NULL,
Value varchar(200) NOT NULL
)
;
The downside to data normalisation is that it makes it more difficult to get the data back (Murphys Law: A database stores data and is unwilling to show it back once it has hold of the data).
If this is just to store data in a database that is completely used outside the database forever and a day then go with the first table creation.
If not, please use normalisation to allow fast and efficient analysis of the data through database tools.

SQL Debit and Credit tables

I got a database project from my university to finish, but I am stack at the structure of debit and credit table that how to make it in SQL Server, my code is shown here:
create table AcCat
(
CatID smallint Primary Key,
CatName nvarchar(20)
)
Create Table Accounts
(
AcID int Primary key,
AcNumber int,
AcName nvarchar(20),
AcCategory smallint references AcCat(CatID)
)
Create Table Transactions
(
TrnRef bigint primary key identity (1,1),
TrnDate datetime
)
Create Table Voucher
(
VID bigint primary key identity (1,1),
TranRef bigint references Transactions(TrnRef),
AccountNo int references Accounts(AcID),
DrCr nvarchar(2),
Amount money,
Narration nvarchar(100)
)
Create Table Voucher_2
(
V2ID bigint primary key identity (1,1),
V2TranRef bigint references Transactions(TrnRef),
V2DebitAc int references Accounts(AcID),
V2CreditAc int references Accounts(AcID),
Amount money,
Narration nvarchar(100)
)
I don't know above table structure are correct or not, but I am stuck at the Voucher and Voucher_2 tables that which one I should use for my Database.
The tables output is following
My tables Output
Either one seems serviceable. Are you given example queries that should be run over your system? If so, have you tried writing those queries and seeing whether one or other of your structures makes all of those queries harder or simpler? Also, have you considered what integrity constraints you may wish the database to enforce?
For instance, finding the current balance of an account can be reasonably performed using either structure.:
SELECT
ac.AcNumber,
SUM(CASE WHEN DrCr = 'Cr' THEN Amount
ELSE -Amount END) as Balance
FROM
Accounts ac
inner join
Voucher v
on
ac.AcID = v.AccountNo
WHERE
ac.AcNumber = 1010
GROUP BY
ac.AcNumber
SELECT
ac.AcNumber,
SUM(CASE WHEN V2DebitAc = V2CreditAc THEN 0
WHEN V2CreditAc = ac.AciD THEN Amount
ELSE -Amount END) as Balance
FROM
Accounts ac
inner join
Voucher_2 v
on
ac.AcID = v.V2DebitAc or
ac.AcID = v.V2CreditAc
WHERE
ac.AcNumber = 1010
GROUP BY
ac.AcNumber
If all transactions are required to be balanced, how will you ensure that there are always pairs of rows in Voucher that match each other?
If you have to apply interest of other account corrections, what account will you match those with in Voucher_2?
If you haven't been given any scenarios to work against, try to conjure some up like the above and see how well they fit. Without further information though, I'd say either will probably work.
One thing I'd serious recommend fixing though - having all of AcNumber, AccountNum and AcID seems like a recipe for confusion. I'd probably just use AcID everywhere outside of the Accounts table unless you want to go one step further and just use AcNumber as a natural key and use it everywhere and remove AcID from the picture. Certainly I didn't expect (before writing the queries) that I'd find AccountNum also in the picture and it's not the same thing as AcNumber.
Where possible I'd advise using as few names as possible. Ideally, everywhere in your schema that you encounter a particular column name, it should mean the same concept, and you shouldn't encounter the same concept under any other names.

Creating a table specifically for tracking change information to remove duplicated columns from tables

When creating tables, I have generally created them with a couple extra columns that track change times and the corresponding user:
CREATE TABLE dbo.Object
(
ObjectId int NOT NULL IDENTITY (1, 1),
ObjectName varchar(50) NULL ,
CreateTime datetime NOT NULL,
CreateUserId int NOT NULL,
ModifyTime datetime NULL ,
ModifyUserId int NULL
) ON [PRIMARY]
GO
I have a new project now where if I continued with this structure I would have 6 additional columns on each table with this type of change tracking. A time column, user id column and a geography column. I'm now thinking that adding 6 columns to every table I want to do this on doesn't make sense. What I'm wondering is if the following structure would make more sense:
CREATE TABLE dbo.Object
(
ObjectId int NOT NULL IDENTITY (1, 1),
ObjectName varchar(50) NULL ,
CreateChangeId int NOT NULL,
ModifyChangeId int NULL
) ON [PRIMARY]
GO
-- foreign key relationships on CreateChangeId & ModifyChangeId
CREATE TABLE dbo.Change
(
ChangeId int NOT NULL IDENTITY (1, 1),
ChangeTime datetime NOT NULL,
ChangeUserId int NOT NULL,
ChangeCoordinates geography NULL
) ON [PRIMARY]
GO
Can anyone offer some insight into this minor database design problem, such as common practices and functional designs?
Where i work, we use the same construct as yours - every table has the following fields:
CreatedBy (int, not null, FK users table - user id)
CreationDate (datetime, not null)
ChangedBy (int, null, FK users table - user id)
ChangeDate (datetime, null)
Pro: easy to track and maintain; only one I/O operation (i'll come to that later)
Con: i can't think of any at the moment (well ok, sometimes we don't use the change fields ;-)
IMO the approach with the extra table has the problem, that you will have to reference somehow also the belonging table for every record (unless you only need the one direction Object to Tracking table). The approach also leads to more I/O database operations - for every insert or modify you will need to:
add entry to Table Object
add entry to Tracking Table and get the new Id
update Object Table entry with the Tracking Table Id
It would certainly make the application code that communicates with the DB a bit more complicated and error-prone.

Sql Server high performance insert in two related tables

Sirs,
I have the following physical model below, resembling an class table inheritance like the pattern from Fowler (http://martinfowler.com/eaaCatalog/classTableInheritance.html)
CREATE TABLE [dbo].[ProductItem] (
[IdProductItem] INT IDENTITY (1, 1) NOT NULL,
[IdPointOfSale] INT NOT NULL,
[IdDiscountRules] INT NOT NULL,
[IdProductPrice] INT NULL);
CREATE TABLE [dbo].[Cellphone] (
[IdCellphone] INT IDENTITY (1, 1) NOT NULL,
[IdModel] INT NOT NULL,
[IMEI] NVARCHAR (150) NOT NULL,
[IdProductItem] INT NULL
);
ProductItem is my base class. It handles all actions related to the sales. Cellphone is a subclass from ProductItem. It adds the atributes and behavior specific that I need to use when I sell an cellphone (IMEI number, activate the cell phone etc)
I need to track each item of the inventory individually. When I receive a batch of 10.000 cellphone, I need to load all this information in my system. I need to create the cellphones and the productitem in my database.
If it was only one table, it is easy to use bulk insert. But, in my case I have an base class with some diferent subclasses represented by tables. What is the best approach to handle this task?
Regards
Camilo
If you're ok with buik inserts, it's still easiest to build a little script to build the tables using an appropriate sequence for referential integrity - in your case probably product, then instances of product (cellphones).