SQL Server search between numbers in varchar column - sql

I have a table Invoices with InvoiceNumber as varchar(32)
The customer can modify how will be their invoices format, like: INV00001, 000001, I00001, etc., so when it's configured, the program each time that is created a invoice it will increment the invoice number so it can be unique
I would like to search invoices but using integer values like from: 2 to 10, like this:
SELECT * FROM Invoices WHERE InvoiceNumber >= '2' AND InvoiceNumber <= '10'
How I can do that with a varchar field?
EDIT: Customer set the format like they want and most of them never change it, most of them use three chars and the rest numbers like: INV0000001
This is not my database, I'm just developing an addon for this app, can't change anything in the DB
InvoiceNumber
-------------
INV00260
INV00261
INV00262
INV00263
INV00264
INV00265
INV00266
INV00267
INV00268
A customer want to search invoice using a between values, let's say he wants to search invoice between INV00262 and INV00267, the customer wants to search by the number, the result should be:
INV00262
INV00263
INV00264
INV00265
INV00266
INV00267
But using integer values like: WHERE InvoiceNumber >= '262' AND InvoiceNumber <= '267'

Assuming that your InvoceNmber contains valid integer values just stored as string ..
You could cast as INT the string eg:
SELECT * FROM Invoices WHERE cast(InvoiceNumber AS INT)>= 2 AND InvoiceNumber <= 10

I believe a more effective use of indexes would work this way. Compare query plans with the accepted answer to see if there's a big difference.
select * from T
where InvoiceNumber between
'INV' + right('0000' + cast(<start> as varchar(5)) and
'INV' + right('0000' + cast( <end> as varchar(5));
It's also a bit simpler and the arguments only need to be referenced once which can make a difference in client code.

Related

SQL-Server drill down in an other table (group by)

OK, I'm quite new to SQL and didn't get to much training!
I'm using SSMS to create stored procedures and open them in Excel.
The code below work just fine, but I need to add a drill down to get more info on some lines.
We need to follow what was invoice and paid on a batch of contracts for our project. Each contract have multiple lines with a description and a couple of other fields(reference, line #, G/L # etc). Plus we have the value of the line, the amount that was invoice for this line and the amount that was paid.
Main table 'CSCOMVTL' have the basic infos including the base value and the invoice amount, but not the paid amount.
'JRAPRVTL' is the list of all invoices with; invoice no., invoice date, invoiced amount and paid amount that we may need to see.
So for each base line, we need a +/- button to show/hide details of the invoice.
Invoice amount and paid amount could be from a rollup, but the number and date won't be on the parent line. If they could be in the same column as other field not needed it would be great, but I could live with 2 extra columns.
Thanks!
ALTER PROCEDURE [dbo].[marpt_qmd_AccPmt_DetailsST]
#contrat varchar(30), #projet varchar(30)
AS
BEGIN
CREATE TABLE #RPT
(
Ligne INT,
Lien INT,
Act VARCHAR (10),
Descr VARCHAR (90),
MntBase DECIMAL (20,2),
MntFact DECIMAL (20,2),
Modif VARCHAR (40),
Descr3 VARCHAR (90),
Lien2 INT,
MntPy DECIMAL (20,2) default '0',
)
INSERT INTO #RPT (Ligne, Lien, Act, Descr, MntBase, MntFact)
SELECT ROW, DETAILCHANGEORDERCOU, ACTIVITY, DESCRIPTION, AMOUNT, INVOICE
FROM cscomvtl
WHERE PROJECTNUMBER = #projet
and LTRIM(RTRIM(PONUMBER)) = #contrat
UPDATE #RPT
SET Modif=m.CHANGEORDERNUMBER, Descr3=m.DESCRIPTION, Lien2=m.CHANGEORDERCOUNTER
FROM cscomac m, #RPT r
where m.COUNTER=r.Lien
UPDATE #RPT
SET MntPy=payment
FROM #RPT r, (select POLINE, sum(payment) payment from jraprvtl where PROJECTNO=#projet
and LTRIM(RTRIM(PURCHASEORDER))=#contrat group by POLINE) d
where r.Ligne=d. POLINE
SELECT
Ligne as 'Ligne',
Act as 'Act.',
Descr as 'Description 1',
MntBase as '$ Base',
MntFact as '$ Invoiced',
Modif as 'Num. Modif.',
Descr3 as 'Description 2',
MntPy as '$ Paid'
FROM #RPT
Order by Ligne
Drop table #RPT
First off, take the time & learn SQL. It's an invaluable tool in your toolkit!
Okay, enough of the lecture. In looking through your code, you don't seem to really need the temp table #rpt, you just need to understand JOINs. Hopefully this SQL will get you what you are looking for:
SELECT vtl.ROW AS Ligne, vtl.DETAILCHANGEORDERCOU AS Lein, vtl.ACTIVITY AS Act,
vtl.DESCRIPTION AS Descr, vtl.AMOUNT AS MntBase, vtl.INVOICE AS MntFact,
mac.CHANGEORDERNUMBER AS Modif, mac.DESCRIPTION AS Descr3, mac.CHANGEORDERCOUNTER AS Lien2,
sum(jrap.payment) AS MntPy
FROM cscomvtl AS vtl
LEFT OUTER JOIN cscomac AS mac
ON vtl.detailchangeordercou = mac.counter
LEFT OUTER JOIN jraprvtl AS jrap
ON vtl.row = jrap.poline
WHERE projectnumber = #projet AND LTRIM(RTRIM(ponumber)) = #contrat
GROUP BY vtl.row, vtl.detailchangeordercou, vtl.activity, vtl.description, vtl.amount,
vtl.invoice, mac.changeordernumber, mac.description, mac.changeordercounter
You will likely have to tweak it to fit what you're trying to do in Excel, since you really didn't give much to go on there.

Postgresql query for every day sold stock count

I have project on CRM which maintains product sales order for every organization.
I want to count everyday sold stock which I have managed to do by looping over by date but obviously it is a ridiculous method and taking more time and memory.
Please help me to find out it in single query. Is it possible?
Here is my database structure for your reference.
product : id (PK), name
organization : id (PK), name
sales_order : id (PK), product_id (FK), organization_id (FK), sold_stock, sold_date(epoch time)
Expected Output for selected month :
organization | product | day1_sold_stock | day2_sold_stock | ..... | day30_sold_stock
http://sqlfiddle.com/#!15/e1dc3/3
Create tablfunc :
CREATE EXTENSION IF NOT EXISTS tablefunc;
Query :
select "proId" as ProductId ,product_name as ProductName,organizationName as OrganizationName,
coalesce( "1-day",0) as "1-day" ,coalesce( "2-day",0) as "2-day" ,coalesce( "3-day",0) as "3-day" ,
coalesce( "4-day",0) as "4-day" ,coalesce( "5-day",0) as "5-day" ,coalesce( "6-day",0) as "6-day" ,
coalesce( "7-day",0) as "7-day" ,coalesce( "8-day",0) as "8-day" ,coalesce( "9-day",0) as "9-day" ,
coalesce("10-day",0) as "10-day" ,coalesce("11-day",0) as "11-day" ,coalesce("12-day",0) as "12-day" ,
coalesce("13-day",0) as "13-day" ,coalesce("14-day",0) as "14-day" ,coalesce("15-day",0) as"15-day" ,
coalesce("16-day",0) as "16-day" ,coalesce("17-day",0) as "17-day" ,coalesce("18-day",0) as "18-day" ,
coalesce("19-day",0) as "19-day" ,coalesce("20-day",0) as "20-day" ,coalesce("21-day",0) as"21-day" ,
coalesce("22-day",0) as "22-day" ,coalesce("23-day",0) as "23-day" ,coalesce("24-day",0) as "24-day" ,
coalesce("25-day",0) as "25-day" ,coalesce("26-day",0) as "26-day" ,coalesce("27-day",0) as"27-day" ,
coalesce("28-day",0) as "28-day" ,coalesce("29-day",0) as "29-day" ,coalesce("30-day",0) as "30-day" ,
coalesce("31-day",0) as"31-day"
from crosstab(
'select hist.product_id,pr.name,o.name,EXTRACT(day FROM TO_TIMESTAMP(hist.sold_date/1000)),sum(sold_stock)
from sales_order hist
left join product pr on pr.id = hist.product_id
left join organization o on o.id = hist.organization_id
where EXTRACT(MONTH FROM TO_TIMESTAMP(hist.sold_date/1000)) =5
and EXTRACT(YEAR FROM TO_TIMESTAMP(hist.sold_date/1000)) = 2017
group by hist.product_id,pr.name,EXTRACT(day FROM TO_TIMESTAMP(hist.sold_date/1000)),o.name
order by o.name,pr.name',
'select d from generate_series(1,31) d')
as ("proId" int ,product_name text,organizationName text,
"1-day" float,"2-day" float,"3-day" float,"4-day" float,"5-day" float,"6-day" float
,"7-day" float,"8-day" float,"9-day" float,"10-day" float,"11-day" float,"12-day" float,"13-day" float,"14-day" float,"15-day" float,"16-day" float,"17-day" float
,"18-day" float,"19-day" float,"20-day" float,"21-day" float,"22-day" float,"23-day" float,"24-day" float,"25-day" float,"26-day" float,"27-day" float,"28-day" float,
"29-day" float,"30-day" float,"31-day" float);
Please note, use PostgreSQL Crosstab Query. I have used coalesce for handling null values(Crosstab Query to show "0" when there is null data to return).
Following query will help to find the same:
select o.name,
p.name,
sum(case when extract (day from to_timestamp(sold_date))=1 then sold_stock else 0 end)day1_sold_stock,
sum(case when extract (day from to_timestamp(sold_date))=2 then sold_stock else 0 end)day2_sold_stock,
sum(case when extract (day from to_timestamp(sold_date))=3 then sold_stock else 0 end)day3_sold_stock,
from sales_order so,
organization o,
product p
where so.organization_id=o.id
and so.product_id=p.id
group by o.name,
p.name;
I just provided logic to find for 3 days, you can implement the same for rest of the days.
basically first do basic joins on id, and then check if each date(after converting epoch to timestamp and then extract day).
You have a few options here but it is important to understand the limitations first.
The big limitation is that the planner needs to know the record size before the planning stage, so this has to be explicitly defined, not dynamically defined. There are various ways of getting around this. At the end of the day, you are probably going to have somethign like Bavesh's answer, but there are some tools that may help.
Secondly, you may want to aggregate by date in a simple query joining the three tables and then pivot.
For the second approach, you could:
You could do a simple query and then pull the data into Excel or similar and create a pivot table there. This is probably the easiest solution.
You could use the tablefunc extension to create the crosstab for you.
Then we get to the first problem which is that if you are always doing 30 days, then it is easy if tedious. But if you want to do every day for a month, you run into the row length problem. Here what you can do is create a dynamic query in a function (pl/pgsql) and return a refcursor. In this case the actual planning takes place in the function and the planner doesn't need to worry about it on the outer level. Then you call FETCH on the output.

How to specify a decimal filter in 'select into table where' in ABAP?

I need a query like this in ABAP, but this doesn't work.
SELECT * FROM table
INTO i_tab
WHERE amount = 100,15
I've tried:
WHERE amount = '100,15' but that doesn't work either.
How to specify the decimal in my where syntax?
The correct syntax is:
SELECT *
FROM table
INTO i_tab
WHERE amount = '100.15'
I outsmarted it by changing the logic into
WHERE amount > 100 AND amount < 101

Why is this SQL query wrong?

SELECT
CD.CountryID, CD.GrossLimit, CD.UnsecuredLimit,
SUM(LT1.Amount), SUM(LT1.Unsecured),
(100*SUM(LT1.Unsecured) / CD.UnsecuredLimit) as PercOverCountryLimit
FROM CountryDetail CD
INNER JOIN
(
SELECT CompanyName AS Company, CollateralSName as Collateral, SUM(Amount) AS Amount,
SUM(Usecured) AS Unsecured, LT.Date as Date, Max(CountryID) as CountryID
FROM Loanstotal LT
WHERE YearMonth = #YearMonth
GROUP BY CompanyName, CollateralSName, LT.Date
) LT1
GROUP BY CountryID, GrossLimit, UnsecuredLimit
ON CD.CountryID = LT1.CountryID
Well I see some possible problems right off
First your group by is in the incorrect place, it needs to be after the ON clause in the join not before it.
Possible issue with a typo: SUM(Usecured) should that be SUM(Unsecured)?
Next depending on what type of data is in the fields you are summing up, you may have a problem with integer math. An integer divided by an integer will give an integer result (3/2 = 1 for example) so you must convert one value to a numeric.
Other issues may be there depending on which version of SQL you are using, You need to specify which database backed to get the best answers. Mine are based on what SQL server would want.

SQL query a range of records that fall within a Min and Max value

For my Realty site I would also like to return the properties that fall within the user's requested price range from two drop down lists MinPrice and MaxPrice (which are also the field values).
Below is my statement thus far. It is working properly aside from the above requirement.
SELECT busname, email, render_pic,
area,logo, url, email, map,
description, tag, catch_phrase, region
FROM Results
WHERE STYLE LIKE 'varStyle'
AND REGION LIKE 'varRegion'
AND BEDROOMS LIKE 'varBedrooms'
AND BATHROOMS LIKE 'varBathrooms'
ORDER BY ID desc
Thank you SO MUCH in advance!
and Price between #minprice and #maxprice
Edit: To cover what #paxdiablo is suggesting, although I have no idea why a house would have anything besides a price...
and (minprice between #minprice and #maxprice
or maxprice between #minprice and #maxprice
or #minprice between minprice and maxprice)
SELECT busname, email, render_pic,
area,logo, url, email, map,
description, tag, catch_phrase, region
FROM Results
WHERE STYLE LIKE 'varStyle'
AND REGION LIKE 'varRegion'
AND BEDROOMS LIKE 'varBedrooms'
AND BATHROOMS LIKE 'varBathrooms'
AND Price between varMinPrice and varMaxPrice
ORDER BY ID desc
Having two ranges that overlap (in the input and record) is a little ticky but you should try:
SELECT
busname, ...
FROM Results
WHERE STYLE LIKE &varStyle
AND REGION LIKE &varRegion
AND BEDROOMS LIKE &varBedrooms
AND BATHROOMS LIKE &varBathrooms
AND (
MINPRICE between &MinPrice and &MaxPrice
OR MAXPRICE between &MinPrice and &MaxPrice
OR (MINPRICE <= &MinPrice AND MAXPRICE >= &MaxPrice)
)
ORDER BY ID desc
This will match if any price within your row min/max range is within your search min/max range (including when row min/max is entirely within search range) or if the entire search range is within your row range, which is what I think you were after.
In addition, you may want to rethink using LIKE unless those var... variable are actually allowed to have wild-cards. Some less intelligent DBMS' may not convert them into a more efficient = operation automatically.
This is how I would perform this type of query:
Only pass in values that are chosen by the user anything else that they don't specify leave as they are defaulted to NULL in the sproc below. I guessed at the parameter types but you get the idea. Also have added '%' so that the Region and Style are wild-carded.
The below query will return matching results based on none, any or all combinations of parameters supplied.
CREATE PROCEDURE [dbo].[spGetProperties]
#style VARCHAR(50) = NULL
,#region VARCHAR(50) = NULL
,#bedrooms TINYINT = NULL
,#bathrooms TINYINT = NULL
,#minPrice INT = NULL
,#maxPrice INT = NULL
AS
BEGIN
SELECT busname, email, render_pic,
area,logo, url, email, map,
description, tag, catch_phrase, region
FROM Results
WHERE (#style IS NULL OR STYLE LIKE '%' + #style + '%')
AND (#region IS NULL OR REGION LIKE '%' + #region + '%')
AND (#bedrooms IS NULL OR BEDROOMS >= #bedrooms)
AND (#bathrooms IS NULL OR BATHROOMS >= #bathrooms)
AND (#minPrice IS NULL OR MINPRICE >= #minPrice)
AND (#maxPrice IS NULL OR MAXPRICE <= #maxPrice)
ORDER BY ID desc
END