SQL Server : Search Between Characters in UK Postcode Unit Field - sql-server

As a solution to a postcode lookup I have split a postcode database into a the separate columns for Area, District, Sector, Unit. I have even split out the characters that could be in District like the A and B in W1A and W1B etc.
I am wanting to search for a postcode like B46 3BA and have got as far as returning details as below.
The SQL query used thus far is
SELECT
StationID, FromPostcode, ToPostcode, FromPostCodeArea,
FromPostCodeDistrict, FromPostCodeDistrictChar,
FromPostCodeSector, FromPostCodeUnit,
ToPostCodeArea, ToPostCodeDistrict,
ToPostCodeDistrictChar, ToPostCodeSector, ToPostCodeUnit
FROM
Station
WHERE
(FromPostCodeArea = 'B')
AND (3 BETWEEN FromPostCodeSector AND ToPostCodeSector)
AND (46 BETWEEN FromPostCodeDistrict AND ToPostCodeDistrict)
My main issues for legacy application reasons is I do not have access to the Select query and can only change the WHERE clause. I just need it to return the single row in this case row with stationid 3321.
But I am totally lost on how to take this any further
Answer As suggested by Jamie makes the sql
SELECT
StationID, FromPostcode, ToPostcode, FromPostCodeArea,
FromPostCodeDistrict, FromPostCodeDistrictChar,
FromPostCodeSector, FromPostCodeUnit,
ToPostCodeArea, ToPostCodeDistrict,
ToPostCodeDistrictChar, ToPostCodeSector, ToPostCodeUnit
FROM
Station
WHERE
(FromPostCodeArea = 'B')
AND (3 BETWEEN FromPostCodeSector AND ToPostCodeSector)
AND (46 BETWEEN FromPostCodeDistrict AND ToPostCodeDistrict)
AND ('B46 3BA' BETWEEN FromPostCode AND ToPostCode)
Seems to do the trick on a test run of 2000 random postcodes.

Related

SQL Server & MS Access separate Views for data entry and read only forms?

I'm working on a small company information system using MS Access as the front end and SQL Server 2019 Express as the back end. I am a bit confused about views at the moment.
Here is what I have:
CREATE FUNCTION dbo.DisplayCurrencyFormat
(
#Amount DECIMAL(10,2),
#Currency INT
)
RETURNS NVARCHAR(100)
AS
BEGIN
RETURN
CASE
WHEN #Currency = 1 THEN FORMAT(#Amount, 'C', 'cs-cz')
WHEN #Currency = 2 THEN FORMAT(#Amount, 'C', 'de-ch')
WHEN #Currency = 3 THEN FORMAT(#Amount, 'C', 'en-us')
WHEN #Currency = 4 THEN FORMAT(#Amount, 'C', 'de-de')
END
END
CREATE VIEW v_PurchaseOrderLines
AS
SELECT tbl1PurchaseOrderDetails.PurchaseOrderDetailID,
tbl1PurchaseOrderDetails.PurchaseOrderID,
tbl1Products.ProductName,
tbl1PurchaseOrderDetails.Config,
dbo.DisplayCurrencyFormat(ListPrice,CurrencyID) AS ListPrice,
tbl1PurchaseOrderDetails.Quantity,
FORMAT(tbl1PurchaseOrderDetails.Discount, 'P0') AS Discount,
dbo.DisplayCurrencyFormat(UnitPrice,CurrencyID) AS UnitPrice,
dbo.DisplayCurrencyFormat(UnitPrice*Quantity,CurrencyID) AS TotalPrice,
FORMAT (tbl1PurchaseOrderDetails.VAT, 'P0') AS VAT,
dbo.DisplayCurrencyFormat(UnitPrice*Quantity*(1+VAT),CurrencyID) AS TotalPriceVAT,
tbl1PurchaseOrderDetails.ExpectedDelivery,
tbl1PurchaseOrderDetails.Notes
FROM tbl1PurchaseOrderDetails JOIN tbl1Products ON tbl1PurchaseOrderDetails.ProductID = tbl1Products.ProductID
;
GO
CREATE VIEW v_PurchaseOrderLines_DE
AS
SELECT tbl1PurchaseOrderDetails.PurchaseOrderDetailID,
tbl1PurchaseOrderDetails.PurchaseOrderID,
tbl1PurchaseOrderDetails.ProductID,
tbl1PurchaseOrderDetails.Config,
tbl1PurchaseOrderDetails.Quantity,
tbl1PurchaseOrderDetails.Discount,
tbl1PurchaseOrderDetails.UnitPrice,
tbl1PurchaseOrderDetails.CurrencyID,
tbl1PurchaseOrderDetails.VAT,
tbl1PurchaseOrderDetails.ListPrice,
dbo.DisplayCurrencyFormat(UnitPrice*Quantity,CurrencyID) AS TotalPrice,
dbo.DisplayCurrencyFormat(UnitPrice*Quantity*(1+VAT),CurrencyID) AS TotalPriceVAT,
tbl1PurchaseOrderDetails.ExpectedDelivery,
tbl1PurchaseOrderDetails.Notes
FROM tbl1PurchaseOrderDetails
;
This works quite well but I'm stuck with 2 views. I'm not able to use any view with FORMAT function or joins inside my data entry forms, it will not accept any changes, so the first view is used for the read only form (looking at purchase orders). However I still need to see calculated total prices in real time on my data entry form, that's why I can't feed data directly from the table.
The second view is then used for editing purchase orders.
Is there some workaround how to do all this within a single view, or am I stuck with 2 views for every entity like this one?
Thanks a lot for any tips.
Linked Views with JOINs are editable in Access, if the PK of the underlying table you want to edit is included in the view, and you specify it as PK when linking the view.
Percent formatting can be done in the form.
Currency formatting: you simplify your life and the view by putting the currency symbol into a separate field in view and form. But it is less perfect. :)
It will still depend on your exact requirements if you can get away with a single view for list display vs. editing. It is not always possible.

How to link DOCUVALUE table to related business metadata

I am trying to pull a report of all the documents referenced in AX, and I'm having a heck of a time figuring out the AX database structure. Ideally I want to pull a list of documents and the Journal / Batch # each is associated with.
In our AX environment, all documents are stored on a share (i.e. they're not actually stored as BLOBs in the AX database).
It looks like the DOCUVALUE table is the principal table that references the documents, having the ORIGINALFILENAME and other columns that seem to "point" to the files on the AX share. But DOCUVALUE doesn't contain any useful business metadata.
After a bit of exploring, it looks like like the DOCUREF table relates to DOCUVALUE (DOCUVALUE.RECID = DOCUREF.VALUERECID) which helps a little - gives you the Company #, but that's about it.
After a bit more exploring, it looked like it would be possible to join across to LEDGERJOURNALTABLE as shown below:
select ljt.journalnum, filename + '.' + filetype filename, ljt.name journal_name,
dr.refcompanyid, convert(varchar(10), ljt.posteddatetime,111) posted_date,
ljt.createdby, convert(numeric, ljt.journaltotalcredit) journalamount
from LEDGERJOURNALTABLE ljt, DOCUREF dr, DOCUVALUE dv
where dv.RECID = dr.VALUERECID and dr.refrecid = ljt.recid
order by 1,2
This looked promising, so I pulled out a data listing and asked one of our key business users to review the results. She indicated that it was accurate to some extent, but there were other areas where the document referenced just didn't have any relation to the JournalNum in the listing.
So - I'm at a bit of a dead end - I've spent further time generating SQL statements to harvest data using specific RECID values, trying other joins, but each time I just disappear down a rabbit hole.
Any ideas? Any help gratefully received!!
The AX document management framework is designed so that a document can be attached to any data row in any table. What you're trying to do is far easier in AX, but we'll stick with SQL for the question.
The problem you're having is you don't know the reference objects because you're ignoring REFTABLEID.
The key fields that connect a denormalized "document" to the associated business data are REFTABLEID, REFCOMPANYID, and REFRECID (you already have the last one).
So start with this query below:
SELECT sd.NAME
,sd.SQLNAME
,dr.*
,dv.*
FROM DOCUREF dr
,DOCUVALUE dv
,SQLDICTIONARY sd
WHERE dv.RECID = dr.VALUERECID
AND sd.TABLEID = dr.REFTABLEID
AND sd.FIELDID = 0 -- Indicates it is a table and not a table field
AND sd.NAME = 'LEDGERJOURNALTABLE' -- Instead of hardcoding, join & query
You'll have to get creative depending on your use with SQL, You'll want to remove the hardcoded 'LEDGERJOURNALTABLE' and then use sd.SQLNAME to join to the actual SQL table. Then if that SQL table has DataAreaId, you'd likely want to join it to dr.REFCOMPANYID.
Or you can hardcode the tables or whatever you want to do. You should be aware you can attach documents to journal headers OR lines...or many other rows for that matter.
Just start exploring the data and you should be able to figure out what you want with that query above.
So for your sample query, you can see I added 2 lines. Your query will only work when joined for LedgerJournalTable. You'll have to do some dynamic SQL or use a cursor or something if you want to report on every attachment.
SELECT ljt.journalnum
,filename + '.' + filetype filename
,ljt.name journal_name
,dr.refcompanyid
,convert(VARCHAR(10), ljt.posteddatetime, 111) posted_date
,ljt.createdby
,convert(NUMERIC, ljt.journaltotalcredit) journalamount
FROM LEDGERJOURNALTABLE ljt
,DOCUREF dr
,DOCUVALUE dv
WHERE dv.RECID = dr.VALUERECID
AND dr.REFRECID = ljt.RECID
AND dr.REFCOMPANYID = ljt.DATAAREAID -- ADDED
AND dr.REFTABLEID = 211 -- ADDED TableId for LedgerJournalTable
ORDER BY 1
,2

HANA Calc View Place Holder usage when joining in Table Function or Stored Procedure

HANA Version: SP12
All,
I've successfully created Calc Views with INPUT_PARAMETERS as described by Lars in many blogs and forums. While these views work without issue when querying directly for single and multi inputs, I'm encountering an issue with performing joins on the Calc View itself within a stored proc or table function.
Example:
"BASE_SCHEMA"."BASE_TABLE_EXAMPLE" - record count(*) ~ 2million records
Keys: Material (20k distinct), Plant (200 distinct)
"_SYS_BIC"."CA_EXAMPLE_PRODUCTIVITY"
Input Parameters: IP_MATNR (nvarchar (5000)), IP_PLANT (nvarchar(5000))
Issue #1: The maximum value for nvarchar is 5000. Unable to utilize multiple inputs within the parameter if the count of distinct characters are 5000+.
Issue #2: How to use PLACEHOLDER logic in the same method of performing an INNER_JOIN in SQL.
base_data =
select
PLANT
,MATERIAL
from "BASE_SCHEMA"."BASE_TABLE_EXAMPLE"
group by PLANT,MATERIAL;
I would think to perform the below but the output would cause issues when concatenating multiple strings for use within input parameter of nvarchar(5000).
select
string_agg(PLANT,''',''') as PLANT
,string_agg(MATERIAL,''',''') as MATERIAL
into var_PLANT, var_MATERIAL
from
(
select
PLANT
,MATERIAL
from :base_data
);
While I'm successful up to this point, once adding the variables into the PLACEHOLDER of the Calc View, it fails stating that I'm passing too many characters to the IP. Any suggestions??? Thanks in advance.
base_calc =
select
PLANT
,MATERIAL
,MATERIAL_BU
,etc....
from "_SYS_BIC"."CA_EXAMPLE_PRODUCTIVITY"
(PLACEHOLDER."IP_MATNR"=> :var_MATERIAL, --<---Fails here. :(
PLACEHOLDER."IP_PLANT"=> :var_PLANT);
Question raised on SAP SCN. Located here!
Did you tried to use WHERE clause instead of PLACEHOLDER?
base_calc =
select
PLANT,
MATERIAL,
MATERIAL_BU,
etc....
from "_SYS_BIC"."CA_EXAMPLE_PRODUCTIVITY"
WHERE MATERIAL = var_MATERIAL AND PLANT = var_PLANT;

Oracle ROWTOCOL Function oddities

I have a requirement to pull data in a specific format and I'm struggling slightly with the ROWTOCOL function and was hoping a fresh pair of eyes might be able to help.
I'm using 10g Oracle DB (10.2) so LISTAGG which appears to do what I need to achieve is not an option.
I need to aggregate a number of usernames into a string delimited with a '$' but I also need to concatenate another column to to build up email addresses.
select
rowtocol('select username_id from username where user_id = '||s.user_id|| 'order by USERNAME_ID asc','#'||d.domain_name||'$')
from username s, domain d
where s.user_id = d.user_id
(I've simplified the query specific to just this function as the actual query is quite large and all works except for this particular function.)
in the DOMAIN Table I have a number of domains such as 'hotmail.com','gmail.com' etc
I need to concatenate the username, an '#' symbol followed by the domain and all delimited with a '$'
such as ......
joe.bloggs#gmail.com$joeblogs#gmail.com$joe_bloggs#gmail.com
I've battled with this and I've got close but in reverse?!.....
gmail.com$joe.bloggs#gmail.com$joeblogs#gmail.com$joe_bloggs
I've also noticed that if I play around with the delimiter (,'#'||d.domain_name||'$') it has a tendency to drop off the first character as can be seen above the preceding '#' has been dropped from the first email address.
Can anyone offer any suggestions as to how to get this working?
Many Thanks in advance!
Assuming you're using the rowtocol function from OTN, and have tables something like:
create table username (user_id number, username_id varchar2(20));
create table domain (user_id number, domain_name varchar2(20));
insert into username values (1, 'joe.bloggs');
insert into username values (1, 'joebloggs');
insert into username values (1, 'joe_bloggs');
insert into domain values (1, 'gmail.com');
Then your original query gets three rows back:
gmail.com$joe.bloggs
gmail.com$joe_bloggs#gmail.com$joebloggs
gmail.com$joe_bloggs#gmail.com$joebloggs
You're passing the data from each of your user IDs to a separate call to rowtocol, which isn't really what you want. You can get the result I think you're after by reversing it; pass the main query that joins the two tables as the select argument to the function, and have that passed query do the username/domain concatenation - that is a separate step to the string aggregation:
select
rowtocol('select s.username_id || ''#'' || d.domain_name from username s join domain d on d.user_id = s.user_id', '$')
from dual;
which gets a single result:
joe.bloggs#gmail.com$joe_bloggs#gmail.com$joebloggs#gmail.com
Whether that fits into your larger query, which you haven't shown, is a separate question. You might need to correlate it with the rest of your query.
There are other ways to string aggregation in Oracle, but this function is one way, and you already have it installed. I'd look at alternatives though, such as ThomasG's answer, which make it a bit clearer what's going on I think.
As Alex told you in comments, this ROWTOCOL isn't a standard function so if you don't show its code, there's nothing we can do to fix it.
However you can accomplish what you want in Oracle 10 using the XMLAGG built-in function.
try this :
SELECT
rtrim (xmlagg (xmlelement (e, s.user_id || '#' || d.domain_name || '$')).extract ('//text()'), '$') whatever
FROM username s
INNER JOIN domain d ON s.user_id = d.user_id

Convert multiple SQL Server queries into one

I have a page that ask of users opinion about a topic. Their responses are then saved into a table. What I want to do is to check how many users selected an option 1,2,3 and 4.
What I have now are multiple T-SQL queries that run successfully but I believe there is a simplified version of the code I have written. I would be grateful if someone can simplify my queries into one single query. Thank you.
here is sample of data in the database table
enter image description here
$sql4 = "SELECT COUNT(CO) FROM GnAppItms WHERE CO='1' AND MountID='".$mountID."'";
$stmt4 = sqlsrv_query($conn2, $sql4);
$row4 = sqlsrv_fetch_array($stmt4);
$sql5="SELECT COUNT(CO) FROM GnAppItms WHERE CO='2' AND MountID='".$mountID."'";
$stmt5=sqlsrv_query($conn2,$sql5);
$row5=sqlsrv_fetch_array($stmt5);
$sql6="SELECT COUNT(CO) FROM GnAppItms WHERE CO='3' AND MountID='".$mountID."'";
$stmt6=sqlsrv_query($conn2,$sql6);
$row6=sqlsrv_fetch_array($stmt6);
$sql7="SELECT COUNT(CO) FROM GnAppItms WHERE CO='4' AND MountID='".$mountID."'";
$stmt7=sqlsrv_query($conn2,$sql7);
$row7=sqlsrv_fetch_array($stmt7);
You can do it by using group by in sql server
example :
create table a
(id int,
mountid nvarchar(100),
co int,
)
insert into a values (1,'aa',1)
insert into a values (2,'aa',2)
insert into a values (3,'aa',1)
insert into a values (4,'aa',2)
insert into a values (5,'aa',3)
Query
select co,count(co)as countofco from a
where mountid='aa'
group by
co
result
co countofco
1 2
2 2
3 1
Note : Beware of SQL injection when you are writing a sql query, so always use parametrized query. You can edit the above example code and make it as a parametrized query for preventing sql injection

Resources