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.
Related
I need to make a report that
compare the SKUs that are scheduled on the filling lines this week with how long it has been since the same SKU has been running on the line, and thus only those SKUs that have not been running (or have never been) for more than 3 months, displays.
edit : i think i need to write a query that finds the most recent date of every SKU number and then compare it to the SKU number that is used this week and then
show the ones that are older then 3 months. but i have no clue how to do this with keeping the code underneath intact ?
I have no clue how to start i searched and tried a lot but did not succeed
thanks in advance
code to het sku from this week:
`
SELECT
od.odscheduleid
,lc.shortname as line
,ar.erpcode as SKU
,ar.shortname as Article
,od.[PlannedStartInflow]
,od.[PlannedEndInflow]
,st.shortname as 'status'
,od.[ShortName] as 'order'
,od.[ERPCode]
,od.[ASCode]
,od.[PlannedQuantity] as 'PlannedQuantity [PC]'
,cast(od.[PlannedQuantity]*ar.Volume/100 as decimal(12,2)) as 'PlannedQuantity [HL]'
,od.[PlannedChangeoverTime]
,od.[PlannedSpeed]
,od.[PlannedSpeedRatio]
FROM [RM].[TblDatODSchedule] od
inner join [EM].[TblLstLocation] lc on od.locationid=lc.locationid
inner join [RM].[TblLstART] ar on od.artid=ar.artid
inner join [EM].[TblLstStatus] st on od.statusid=st.statusid
WHERE lc.locationid in (#Line) --lc.packagingtype is not null
and plannedendinflow > #StartDate`
Okay let's suppose you have a table such as this:
CREATE TABLE SKU (name varchar(50), last_run datetime);
We can make your query work like this:
SELECT *
FROM SKU
WHERE last_run IS NULL
OR datediff(month, last_run, getdate()) > 3
I have a database with a 'General Ledger', 'Account Types' and 'Chart of Accounts' tables. The layout is as follows:
'Account Types':
AcctTypeID Autonumber Long Integer Not Null Primary Key
TypeName Text(50) Not Null
Description Memo
Credit Yes/No Not Null Default Yes
'Chart of Accounts':
AcctID Long Integer Not Null Primary Key
AcctName Text(30) Not Null
Description Memo
AcctType Long Integer Not Null
'General Ledger':
EntryID Autonumber Long Integer Not Null Primary Key
EntryDate Date/Time Not Null Default #1/1/1900#
EntryType Text(12) Not Null Default "DC"
Description Memo
FromAcct Long Integer Not Null
ToAcct Long Integer Not Null
Taxable Yes/No Not Null Default No
Relationships Between Tables:
One-to-Many from 'Chart of Accounts'->AcctID to 'General Ledger'->FromAcct
One-to-Many from 'Chart of Accounts'->AcctID to 'General Ledger'->ToAcct
One-to-Many from 'Account Types'->TypeID to 'Chart of Accounts'->AcctType
I'm needing to start by fulfilling the following requirements in two different SQL queries:
If ToAcct.AcctType == (Income OR Asset) then add 'General Ledger'.Amount to a TotalRevenue
If ToAcct.AcctType == (Expense OR Liability) then add 'General Ledger'.Amount to TotalExpenses
I've tried these two SQL queries, before I modified my 'Account Types' to include whether they are income/assets or expenses/liabilities:
SELECT SUM(IIF((Credit = TRUE), Amount, 0)) AS RevenueTotal FROM GeneralLedger;
SELECT SUM(IIF((Credit = FALSE), Amount, 0)) AS ExpenseTotal FROM GeneralLedger
These queries worked, but I had the extra checkbox on the General Ledger form for "Credit". In normalizing, I figured it would be better for the account to determine whether it is a debit or a credit account.
After multiple searches on Google and reading I-don't-know-how-many questions and answers, I'm not seeing anything that is similar to what I'm trying to do here.
The output should give me the information needed for creating the Profit & Loss, Income Statement, Business and Tax reports. I believe I can get the SQL queries going for pulling the amounts based on their account, but I'm not sure how to get at the account types' 'Debit' field to determine whether to add or subtract the amount.
If necessary, I may do this inside the C# application that this database will underpin. If I can do it at the SQL Query level, I'd be able to use it in the project as a view, instead of having to code it. Any help at all is greatly appreciated.
After a couple more searches, I found my answer as being that I need to do 4 different queries to accomplish what I was attempting. The appropriate queries turned out to be:
For Total Expenses:
SELECT SUM(Amount) AS TotalExpense
FROM GeneralLedger INNER JOIN ChartOfAccounts ON ChartOfAccounts.AcctID=GeneralLedger.ToAcct
WHERE ChartOfAccounts.AcctType = 4;
For Total Revenue:
SELECT SUM(Amount) AS TotalRevenue
FROM GeneralLedger INNER JOIN ChartOfAccounts ON ChartOfAccounts.AcctID=GeneralLedger.ToAcct
WHERE ChartOfAccounts.AcctType = 3;
For Total Liabilities:
SELECT SUM(Amount) AS TotalLiabilities
FROM GeneralLedger INNER JOIN ChartOfAccounts ON ChartOfAccounts.AcctID = GeneralLedger.ToAcct
WHERE ChartOfAccounts.AcctType = 2;
For Total Assets:
SELECT SUM(Amount) AS TotalAssets
FROM GeneralLedger INNER JOIN ChartOfAccounts ON ChartOfAccounts.AcctID = GeneralLedger.ToAcct
WHERE ChartOfAccounts.AcctType = 1;
It was just a matter of getting my INNER JOIN working with my WHERE clause properly. It's the simple things that kill...
The link that proved most helpful was: StackOverflow: sql - INNER JOIN WHERE clause.
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.
hope to pick on the wisdom of the folks here. (current approach at the bottom)
Please see the SQL Fiddle Link below.
http://sqlfiddle.com/#!17/4a818/1
create table paymentmethod (
methodtype varchar(6) not null,
methodname varchar(6) not null
);
insert into paymentmethod values
('cc', 'mstr'),
('cc', 'visa'),
('cc', 'amex')
;
create table chargepolicy (
accountname varchar(6) not null,
methodtype varchar(6) not null,
methodname varchar(6) not null,
chargerate float not null
);
insert into chargepolicy values
('acct1','cc', 'mstr', 0.02),
('acct1','cc', 'visa', 0.02),
('acct1','cc', 'amex', 0.025),
('acct2','cc', 'all', 0.015),
('acct3','cc', 'amex', 0.03),
('acct3','cc', 'all', 0.02),
('acct4','cc', 'visa', 0.0),
('acct4','cc', 'all', 0.025)
;
select * from chargepolicy, paymentmethod
where chargepolicy.methodtype = paymentmethod.methodtype
and (chargepolicy.methodname = paymentmethod.methodname
or chargepolicy.methodname = 'all')
order by 1,2,3;
So, this a hypothetical case (obviously). I have payment methods like Visa,MasterCard, Amex and then charge rates for each of these methods. The charge rates will vary base on the account. These accounts to method & rate mapping is defined in another table.
Now then, when I have charge rates defined for each method, things work fine (e.g. acct1 and acct2). Things get insteresting - and this is where I need help - when we come to acct3 and acct4. In acct3, I am saying that for Amex the charge should be 3% and for everything else (all - Amex) it should be 2%. Similarly, in acct4, I want charge for Visa to be 0% and for everything else to be 2.5%.
The way current SQL is written, I am getting two values for acct3.amex and acct4.visa.
How can I simplify that. It must be a straight forward thing but I don't believe I am looking at it right.
This is what I have come up with:
http://sqlfiddle.com/#!17/36a1c/6
select *
from
chargepolicy,
paymentmethod
where
chargepolicy.methodtype = paymentmethod.methodtype
and (chargepolicy.methodname = paymentmethod.methodname
or (chargepolicy.methodname = 'all'
and paymentmethod.methodname not in (
select methodname from chargepolicy cp2 where cp2.accountname = chargepolicy.accountname
and cp2.methodname !='all')
))
order by 1,2,3;
But since my actual use case has a lot of additional options to be mapped (e.g. Country, Product, Currency etc), I am not sure if my current approach is scalable - too many nested queries.
My approach would be like this, its much simpler to follow i think.
select
ac.accountname,
pm.methodtype,
pm.methodname,
coalesce(cp1.chargerate,cp2.chargerate) as chargerate
from
paymentmethod as pm
join (select distinct accountname from chargepolicy) as ac on 1=1
left join chargepolicy as cp1 on pm.methodname=cp1.methodname and ac.accountname=cp1.accountname
left join chargepolicy as cp2 on cp2.methodname='all' and ac.accountname=cp2.accountname
order by 1,2,3;
http://sqlfiddle.com/#!17/36a1c/11
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.