Sql Server Compact (SqlCe 4.0) GROUP BY Query Optimization - c#

I have a table Invoices
Structure of Invoices
CREATE TABLE Invoices (
Id int NOT NULL IDENTITY (1, 1),
Depot nvarchar(100) NOT NULL,
InvoiceNo nvarchar(100) NOT NULL,
InvoiceDate datetime NOT NULL,
Licencee nvarchar(255) NOT NULL,
Outlet nvarchar(1024) NOT NULL,
SerialNo int NOT NULL,
ProductName nvarchar(500) NOT NULL,
Size int NOT NULL,
[Case] int NOT NULL,
BeverageSegment nvarchar(100),
/* Keys */
PRIMARY KEY (Id)
)
GO
CREATE INDEX Invoices_BeverageSegment
ON Invoices
(BeverageSegment)
GO
CREATE INDEX Invoices_InvoiceId
ON Invoices
(InvoiceNo)
GO
I have to query for Total Sales for a particular Depot, for a Product on Date, i have approx 1,35,850 in the Table, the Query is taking 47 minute.
I do not have much expertise in database system, i have checked for Query Optimization for SqlCe but none of them helps in this condition.
My query :
SELECT
Depot,
InvoiceDate,
ProductName,
Size,
SUM([Case]) as Cases
FROM Invoices
GROUP BY
Depot,
InvoiceDate,
ProductName,
Size

Creating a non clustered index on all the four columns Depot, InvoiceDate, ProductName, Size will increase the performance.
Create NonClustered Index Index_Name
on
Invoices ( Depot, InvoiceDate, ProductName, Size)

Related

C# / SQL Determine matching score based on properties

On a project where we have SQL tables called Products and Conditions, we want to determine which product belongs to which most matching condition, because a product can belong to multiple conditions.
Is there a way to do this in C# or SQL?
Below you can find a shorted version of the tables with the properties that we want to match on:
CREATE TABLE Products
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(1,1),
[Property1] SMALLINT NULL,
[Property2] SMALLINT NULL,
[Property3] NVARCHAR(20) NULL,
[Property4] NVARCHAR(20) NULL
)
CREATE TABLE Conditions
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(1,1),
[Property1] SMALLINT NULL,
[Property2] SMALLINT NULL,
[Property3] NVARCHAR(20) NULL,
[Property4] NVARCHAR(20) NULL
)
As a result we want for each product the conditions and sorted by most matching score based on the 4 properties.
Because we have 4 properties, the resulting score could be 0 / 25 / 50 / 75 / 100.
In sql you can join the two tables on matching properties and use iif method to compute the total score and order the results by the total score like below :
Select * from (
Select p.*, c.*,
iif([Property1] = p.[Property1],25,0) +
iif([Property2] = p.[Property2],25,0) +
iif([Property3] = p.[Property3],25,0) +
iif([Property4] = p.[Property4],25,0) [TotalScore]
from Products p inner join Conditions c
on c.[Property1] = p.[Property1] or
c.[Property2] = p.[Property2] or
c.[Property3] = p.[Property3] or
c.[Property4] = p.[Property4]) q
order by TotalScore desc

how do you connect the data from other table or from the users input on my 5th table?

PUTTING DATA ON 5TH TABLE FROM OTHER TABLES OR FROM USERS INPUT
STORED PROCEDURE FOR INSERTING DATA ON IT
I connected it in my windows form.
Table supplier
CREATE TABLE SUPPLIER
(
SUPPLIERID int identity(001,1) PRIMARY KEY NOT NULL,
SUPPLIERNAME varchar(50) NOT NULL,
ADDRESS varchar(50) NOT NULL,
Contact# varchar(50) NOT NULL
)
Table products:
CREATE TABLE PRODUCTS
(
PRODUCTID int identity(301, 1) PRIMARY KEY NOT NULL,
PNAME varchar(50) NOT NULL,
PCOLOR varchar(50)
FOREIGN KEY REFERENCES PRODUCTCOLOR(PRODUCTCOLOR) NOT NULL,
PPRICE INT NOT NULL
)
Table productcolor:
CREATE TABLE PRODUCTCOLOR
(
PRODUCTCOLOR varchar(50) PRIMARY KEY NOT NULL
)
Table customer:
CREATE TABLE CUSTOMER
(
CUSTOMERID int identity(601,1) PRIMARY KEY NOT NULL,
FIRSTNAME varchar(50) NOT NULL,
LASTNAME varchar(50) NOT NULL,
EMAIL varchar(50) NOT NULL ,
ADDRESS varchar(50) NOT NULL,
TELEPHONE varchar(50) NOT NULL,
username varchar(50),
password varchar (50)
)
I want to put(connect) them in the 5th table and create a stored procedure with it
Table orders:
CREATE TABLE ORDERS
(
Cusid int NOT NULL foreign key references CUSTOMER(CUSTOMERID),
Proid int NOT NULL foreign key references PRODUCTS(PRODUCTID),
Supp int NOT NULL foreign key references SUPPLIER(SUPPLIERID),
FNAME VARCHAR(50),
LNAME VARCHAR(50),
PRONAME VARCHAR(50),
SUPNAME VARCHAR(50),
PCOLOR varchar(50)FOREIGN KEY REFERENCES PRODUCTCOLOR(PRODUCTCOLOR)NOT NULL,
QUANTITY VARCHAR(50)primary key NOT NULL
)
Stored procedure:
CREATE PROCEDURE sp_order
#FNAME varchar(50),
#LNAME varchar(50),
#PRONAME varchar(50),
#SUPNAME varchar(50),
#PCOLOR varchar(50),
#QUANTITY int
AS
INSERT INTO ORDERS
VALUES (#FNAME, #LNAME, #PRONAME, #SUPNAME, #PCOLOR, #QUANTITY)
RETURN 0
I don't know if my 5th table is right and my stored procedure.
I've tried many things but it's kinda confusing
If you are not inserting into ALL columns of a table then the INSERT statement must list the specific columns:
INSERT INTO ORDERS (FNAME, LNAME, PRONAME, SUPNAME, PCOLOR, QUANTITY)
VALUES(#FNAME,#LNAME,#PRONAME , #SUPNAME, #PCOLOR, #QUANTITY);
Notice how the column names are specified and also the values are provided.
However, your table has defined NOT NULL columns so you must provide values for those.
Your procedure should look more like this:
CREATE PROCEDURE sp_order
#Cusid int,
#Proid int,
#Supp int,
#FNAME varchar(50),
#LNAME varchar(50),
#PRONAME varchar(50),
#SUPNAME varchar(50),
#PCOLOR varchar(50),
#QUANTITY int
AS
INSERT INTO ORDERS (Cusid, Proid, Supp, FNAME, LNAME, PRONAME, SUPNAME, PCOLOR, QUANTITY)
VALUES(#Cusid, #Proid, #Supp, #FNAME,#LNAME,#PRONAME , #SUPNAME, #PCOLOR, #QUANTITY);
RETURN 0;
Now you have the issue about obtaining the values for those foreign keys. I can't help with that based on the information you have provided.
as an aside you shouldn't name procedures with "sp_" because that is a special prefix that will hit you with a small performance penalty.

How to grab last row in database table with specific requirements?

Okay so I am accepting payments on my site (via Authorize.Net). The payment form redirects to a receipt page.
I will have a column in the database for an invoice code (column InvoiceCode), which is RRC0A in this instance. Then I will have another column for an 8 digit number (column InvoiceNumber). Then I will have InvoiceCode + InvoiceNumber = InvoiceId. For example, the InvoiceId will be RRC0A + 8 numbers. It will increment as such: 00000000, 00000001, 00000002, etc. Therefore the InvoiceId will be RRC0A00000001. I cannot simply increment the column in my database because there will be other InvoiceCodes that also start at 00000000.
I need to increment the InvoiceNumber by one when I add a new row. How can I grab the last InvoiceNumber that was entered into the database? It must be associated with the InvoiceCode RRC0A. This could occur when more than 1 person is making a payment, so I am not sure of the best way.
How can I pad the incrementing InvoiceNumber with 0's in front so that it is always 8 digits?
Using an identity and a computed column you can created you invoice numbers with the correct formatting at the time of insert.
CREATE TABLE [dbo].[Invoices](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Code] [nchar](5) NOT NULL,
[InvoiceNumber] AS ([Code]+right('00000000'+CONVERT([nvarchar](10),[ID]),(8))) PERSISTED,
[Cost] [decimal](18, 2) NOT NULL,
CONSTRAINT [PK_Invoices] PRIMARY KEY CLUSTERED
(
[ID] ASC
)
)
sample bulk insert
INSERT INTO [dbo].[Invoices] ([Code], [Cost])
OUTPUT INSERTED.*
SELECT 'ABC01', 500 UNION ALL
SELECT 'ABC01', 501 UNION ALL
SELECT 'EFG23', 502 UNION ALL
SELECT 'RRAc1', 503 UNION ALL
SELECT 'ABC01', 504
output
ID Code InvoiceNumber Cost
1 ABC01 ABC0100000001 500.00
2 ABC01 ABC0100000002 501.00
3 EFG23 EFG2300000003 502.00
4 RRAc1 RRAc100000004 503.00
5 ABC01 ABC0100000005 504.00
When you insert your records you can get the ID and InvoiceNumber back at the same time.
The values are also persisted so they may be indexed as you would other columns.
SELECT InvoiceCode, MAX(InvoiceID)
FROM yourTable t
GROUP BY InvoiceCode
This should return the latest InvoiceID for each InvoiceCode, but you can add your own WHERE clause to filter it down
As for how to pad-left in sql, check out this answer.
A as in one column is just a bad design
Have composite PK
InvCode (varchar), InvInt (int)
declare #InvCode varchar(20) = 'RRC0A'
insert into invoice (InvCode, InvInt)
OUTPUT INSERTED.InvInt, INSERTED.InvCode
select #InvCode, isnull(max(InvInt),-1) + 1
from invoice
where InvCode = #InvCode;
The isnull will deal with the first one
A single statement is a transaction so I don't think two simultaneous could clobber
Even if they did the PK would be violated so the insert would fail
use a view or a computed column for the formatted invoice number
CREATE TABLE [dbo].[Invoice](
[InvCode] [varchar](10) NOT NULL,
[InvInt] [int] NOT NULL,
[Formatted] AS ([InvCode]+right('00000000'+CONVERT([nvarchar](10),[InvInt]),(8))),
CONSTRAINT [PK_Invoice] PRIMARY KEY CLUSTERED
(
[InvCode] ASC,
[InvInt] ASC
)
You can grab the last InvoiceNumber with a SELECT query.
You can pad the invoice number with the + sign to concatenate two strings, and then use RIGHT() to get the right-most 8 characters.

Update quantity with same column value name

I have this following data in my database table (Items):
Above image shows that row 1 and row 2 have same values.
My question is how can I delete the row 2, but because it detects it have same product name, it will add the quantity? For this example row 2 quantity will be added to row 1 quantity. So row 1 quantity have 20 rather than 10, and the database table have only just 1 row.
Sorry for not providing the code.
SQL INSERT Query for the above image:
INSERT INTO [Items] ([Category], [Name], [Quantity], [Price], [Label], [Status]) VALUES (#Category, #Name, #Quantity, #Price, #Label, #Status)
SQL SELECT Query for the above image:
SELECT [Category], [Name], [Quantity], [Price], [Label], [Status], [ImageData] FROM [Items] WHERE [Status] = #Active ORDER BY [Category] ASC;
The #Active Parameter is Active.
T-SQL Create table:
CREATE TABLE [dbo].[Items] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Category] NVARCHAR (50) NULL,
[Name] NVARCHAR (50) NULL,
[Quantity] SMALLINT NULL,
[Price] DECIMAL (18) NULL,
[Label] NVARCHAR (50) NULL,
[Status] NVARCHAR (50) NULL,
[ImageData] VARBINARY (MAX) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
What I want to do:
I want to delete the second row from database, but before that, it will check first and second row if there is same product name, if there is, then it will delete the last row (which is second row in this example), and update the quantity in the first row with what is the quantity in the second row. If first row have 10 quantity, and second row have 20 quantity, then the first row have 30 quantity, and the second row is gone (deleted)
This SQL will group it for you. You are just summing the price and grouping by the rest of the columns.
SELECT
[Category],
[Name],
SUM([Quantity]),
[Price],
[Status],
[ImageData]
FROM [Items] WHERE [Status] = #Active ORDER BY [Category] ASC
GROUP BY
[Category],
[Name],
[Price],
[Status],
[ImageData]
Ideally you should have a "ProductID" column in this table so that you can group by this instead of relying on the procuct Name being unique.
Here is the update that will update the quantity of the first record with the sum of its quantity plus the quantities in any records with the same category and name that come after it, and then the delete statement that will delete those later records, while leaving your firstone intact:
update items i1
inner join items i2 on i1.category = i2.category and i1.name = i2.name
and i1.id < i2.id
set i1.quantity = i1.quantity + i2.quantity
delete i1 from items i1
inner join items i2 on i1.id > i2.id and
i1.category = i2.category and i1.name = i2.name

Entity Framework, random query paging

This is what I want to achieve:
I want to query my db to return a list of entities
Randomize the list
Store the IDS of items received for future queries
Run a new query on the same table where the IDs are in the list that I have stored
Order by the list that I have stored.
I have managed to achieve step 1, 2, 3, 4 already but step 5 is difficult. Can anyone help me with a query like so:
SELECT *
FROM table_name
WHERE id IN (1,2,3,4....)
ORDER BY (1,2,3,4....)
Thanks in advance
Try
SELECT table_name.*
FROM crazy_sorted_table
LEFT JOIN
table_name ON crazy_sorted_table.ID=table_name.ID
A normal join (equi join) should do the trick , here is sample approach i tested:
/**crazyOrder filled 100 rows with random value from 1-250 in Id**/
CREATE TABLE [dbo].[crazyOrder] (
[Id] INT NOT NULL,
[Area] VARCHAR (50) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
/**Normal order is filled with value from 1-100 sequentially in id**/
CREATE TABLE [dbo].[normalOrder] (
[Id] INT NOT NULL,
[Name] VARCHAR (50) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
create table #tempOrder
(id int)
insert into #tempOrder
Select top 10 Id
from crazyOrder
order by NewID()
go
Select n.*
from normalOrder n
join #tempOrder t
on t.id = n.id
I was able to retrieve the rows in the same order as in the temp table (i used a data generator for the values)

Categories