Below are the two tables.
Table1:
Label value
A 10
A 18
A 15
B 11
B 20
B 10
C 17
C 17
C 18
Table2:
Label count
A 20
A 17
A 11
B 20
B 17
B 17
C 14
C 20
C 19
I'm running this query.
SELECT
Table1."label",
sum("value"),
sum("count")
FROM Table1
LEFT JOIN Table2 ON
Table1."label" = Table2."label"
GROUP BY Table1."label"
Result what i need to get is this.
label value count
A 43 48
B 41 54
C 52 53
But what i get is.
label value count
A 12491 12346
B 213295 1243456
C 1578105 123434
I don't know why I get that result.
Help me out if I'm doing something wrong in the query.
I've just stepped into PostgreSQL and databases.
Your result has three columns.
label, sum(value), sum(count)
so
label sum
A 12491
B 213295
C 1578105
you see is :
a 124 91
b 2132 95
c 15781 105
what's the space ?
SEE MY EXP :
digoal=# create table t1(id int, v int);
CREATE TABLE
digoal=# create table t2(id int, c int);
CREATE TABLE
digoal=# insert into t1 values (1,10);
INSERT 0 1
digoal=# insert into t1 values (1,20);
INSERT 0 1
digoal=# insert into t1 values (1,30);
INSERT 0 1
digoal=# insert into t1 values (2,10);
INSERT 0 1
digoal=# insert into t1 values (2,20);
INSERT 0 1
digoal=# insert into t1 values (2,30);
INSERT 0 1
digoal=# insert into t1 values (3,10);
INSERT 0 1
digoal=# insert into t1 values (3,20);
INSERT 0 1
digoal=# insert into t1 values (3,30);
INSERT 0 1
digoal=# insert into t2 select * from t1;
INSERT 0 9
digoal=# select t1.id,sum(v),sum(c) from t1 left join t2 on t1.id=t2.id group by t1.id;
id | sum | sum
----+-----+-----
1 | 180 | 180
2 | 180 | 180
3 | 180 | 180
(3 rows)
you can set fieldsep to see.
pg93#db-172-16-3-150-> psql -A
psql (9.3.3)
Type "help" for help.
digoal=# \pset fieldsep ,
Field separator is ",".
digoal=# select t1.id,sum(v),sum(c) from t1 left join t2 on t1.id=t2.id group by t1.id;
id,sum,sum
1,180,180
2,180,180
3,180,180
(3 rows)
Related
My table is like this:
ID Code ParentID
-------------------
1 A01 NULL
2 B83 NULL
3 H92 NULL
15 A013 NULL
23 A018 NULL
33 A01899 NULL
44 B8329 NULL
67 B83293 NULL
What I want is to update ParentID to match the ID of the parent code.
A01 is the parent for A013
A01 is the parent for A018
A018 is the parent for A01899
and so on.
You can see the length of A01 is 3 while the child A013 length is 4, the length of A018 is 4 and the child A01899 length is 6.
I can do that with multiple update statements and repeat that for each case.
UPDATE A
SET ParentID = B.ID
FROM Table A
INNER JOIN Table B ON A.Code like B.Code + '%'
WHERE LEN(A.Code) = 4 AND LEN(B.Code) = 3
But the question is how to do that in a single update statement?
You can first find all the relevant matches - similar to what you have - but also the length of the code it matched to. Then find the one with the longest matched code.
CREATE TABLE #TableA (ID int, Code varchar(10), ParentID int);
INSERT INTO #TableA (ID, Code, ParentID)
VALUES
(1 , 'A01' , NULL),
(2 , 'B83' , NULL),
(3 , 'H92' , NULL),
(15, 'A013' , NULL),
(23, 'A018' , NULL),
(33, 'A01899', NULL),
(44, 'B8329' , NULL),
(67, 'B83293', NULL);
WITH A AS
(SELECT TA.ID, TA.ParentID, TB.ID AS TB_ID,
ROW_NUMBER() OVER (PARTITION BY TA.ID ORDER BY TB.Len_Code DESC) AS rn
FROM #TableA TA
INNER JOIN
(SELECT ID, Code, LEN(CODE) AS Len_Code
FROM #TableA
) TB ON TA.Code LIKE TB.Code + '%'
WHERE TA.ID <> TB.ID
)
UPDATE A
SET A.ParentId = A.TB_ID
WHERE A.rn = 1;
Result
ID Code ParentID
1 A01 NULL
2 B83 NULL
3 H92 NULL
15 A013 1
23 A018 1
33 A01899 23
44 B8329 2
67 B83293 44
Just another option.
Significant Digits can be a risky business in the long run. It has been my experience that they tend to have a rather short shelf-life until an exception needs to be made.
In the example below, we allow for up to three characters in distance. We apply the closest first via the coalesce()
Just to be clear, Left Join D may not be necessary if Parents are within 1 or 2 characters. Conversely, this could be expanded if needed Left Join D ...
Example
Declare #YourTable Table ([ID] int,[Code] varchar(50),[ParentID] int)
Insert Into #YourTable Values
(1,'A01',NULL)
,(2,'B83',NULL)
,(3,'H92',NULL)
,(15,'A013',NULL)
,(23,'A018',NULL)
,(33,'A01899',NULL)
,(44,'B8329',NULL)
,(67,'B83293',NULL)
;with cte as (
Select A.*
,PtNr = coalesce(B.ID,C.ID,D.ID)
From #YourTable A
Left Join #YourTable B on left(A.[Code],len(A.[Code])-1)=B.[Code]
Left Join #YourTable C on left(A.[Code],len(A.[Code])-2)=C.[Code]
Left Join #YourTable D on left(A.[Code],len(A.[Code])-3)=D.[Code]
)
Update cte set ParentID=PtNr
Select * From #YourTable
The Update Table
ID Code ParentID
1 A01 NULL
2 B83 NULL
3 H92 NULL
15 A013 1
23 A018 1
33 A01899 23
44 B8329 2
67 B83293 44
I have a table like this:
from | to
-----+-----
23 | 24
24 | 25
25 | 27
27 | 30
45 | 46
46 | 47
50 | 52
53 | 60
I need a SQL Server query that detect chain's and return min (from) and max (to) in each chain (also chain's with one record):
from | to
-----+-----
23 | 30
45 | 47
50 | 52
53 | 60
Here's an approach using a recursive CTE.
CREATE TABLE #chainLinks(linkFrom INTEGER, linkTo INTEGER);
INSERT INTO #chainLinks VALUES (23,24);
INSERT INTO #chainLinks VALUES (24,25);
INSERT INTO #chainLinks VALUES (25,27);
INSERT INTO #chainLinks VALUES (27,30);
INSERT INTO #chainLinks VALUES (45,46);
INSERT INTO #chainLinks VALUES (46,47);
INSERT INTO #chainLinks VALUES (50,52);
INSERT INTO #chainLinks VALUES (53,60);
WITH reccte AS
(
/*Recursive Seed*/
SELECT linkFrom AS chainStart,
linkFrom,
linkTo,
0 as links
FROM #chainLinks as chainLinks
WHERE linkFrom NOT IN (SELECT DISTINCT linkTo FROM #chainLinks)
UNION ALL
/*Recursive Term*/
SELECT
reccte.chainStart,
chainLinks.linkFrom,
chainLinks.linkTo,
links + 1
FROM reccte
INNER JOIN #chainLinks as chainLinks ON reccte.linkTo = chainLinks.linkFrom
)
SELECT chainStart, linkTo AS chainEnd
FROM
(
SELECT chainStart, linkFrom, linkTo, links, ROW_NUMBER() OVER (PARTITION BY chainStart ORDER BY links DESC) AS rn
FROM reccte
)subrn
WHERE rn = 1;
A recursive CTE takes two parts
A recursive seed - This is the part above the UNION where we determine which records from our table begin the recursion. Here we want any linkFrom that isn't also a linkTo
A recusrive term - This is the part below the UNION where we join the cte called reccte back to the original table. This part of the CTE iterates over and over again until that join fails.
In here we are also tracking that links which is just a counter of the number of iterations we have gone through to get to that outputted record. We keep the highest number of links for each starting point chainStart.
Here is the working example: https://rextester.com/JWUW57837
If there are branches within the chains it become a little bit more tricky.
In the sample data below, there's a split on From=12.
So the result shows 2 chains starting from 14.
create table yourtable (
[From] int not null,
[To] int not null,
PRIMARY KEY ([From],[To])
)
GO
✓
insert into yourtable
([From],[To]) values
(2,3),(3,5),(5,4)
,(14,12),(12,15),(15,11),(11,10)
,(12,9)
,(21,23)
GO
9 rows affected
;WITH RCTE_CHAINS AS
(
-- seeding with the start of chains
SELECT [From] AS MinFrom, [From], [To], 0 AS Lvl
, CAST(IIF(EXISTS(
SELECT 1 FROM YourTable n
WHERE n.[From] = t.[To]
),1,0) AS BIT) AS hasNext
FROM YourTable t
WHERE NOT EXISTS
(
SELECT 1
FROM YourTable t2
WHERE t2.[To] = t.[From]
)
UNION ALL
-- looping through the childs
SELECT c.MinFrom, t.[From], t.[To], c.Lvl+1
, CAST(IIF(EXISTS(
SELECT 1 FROM YourTable n
WHERE n.[From] = t.[To]
),1,0) AS BIT) AS hasNext
FROM RCTE_CHAINS c
JOIN YourTable t ON t.[From] = c.[To]
)
SELECT MinFrom AS [From], [To]
FROM RCTE_CHAINS
WHERE hasNext = 0
GO
From | To
---: | -:
21 | 23
14 | 9
14 | 10
2 | 4
db<>fiddle here
Sorry to say i have not in depth knowledge of SQL queries. I have to modify an existing application that records and maintain the customers installments payments.
For this purpose I have a requirement in which i want to copy date of
TableNo1 into TableNo2 except New_Amount(TableNo1) column data, and then remove the remaining rows of TableNo2 for each SalesInvoiceID.
Actually TablNo1 has modified installment payment plan and that is why it is required to modify TableNo2 accordingly.
TableNo1
New_ID SalesInvoiceID InsttNo DueDate New_Amount
1 30 1 2019-05-02 12000
2 30 2 2019-06-02 12000
3 30 3 2019-09-02 4000
4 30 4 2019-12-02 4000
TableNo2
Instt_ID SalesInvoiceID InsttNo DueDate PaymentDate Amount Status
51 30 1 2019-05-02 NULL 0 Up-Coming
52 30 2 2019-06-02 NULL 0 Up-Coming
53 30 3 2019-07-02 NULL 0 Up-Coming
54 30 4 2019-08-02 NULL 0 Up-Coming
55 30 5 2019-09-02 NULL 0 Up-Coming
56 30 6 2019-10-02 NULL 0 Up-Coming
57 30 7 2019-11-02 NULL 0 Up-Coming
58 30 8 2019-12-02 NULL 0 Up-Coming
Required Output (TableNo2)
Instt_ID SalesInvoiceID InsttNo DueDate PaymentDate Amount Status
51 30 1 2019-05-02 NULL 0 Up-Coming
52 30 2 2019-06-02 NULL 0 Up-Coming
53 30 3 2019-09-02 NULL 0 Up-Coming
54 30 4 2019-12-02 NULL 0 Up-Coming
If I'm guessing at the relationship between the tables correctly, this should be all you need, but before you delete any production data you should test this on copies of the tables.
UPDATE t2
SET t2.DueDate = t1.DueDate
FROM
dbo.TableNo2 AS t2
JOIN
dbo.TableNo1 AS t1
ON t1.SalesInvoiceID = t2.SalesInvoiceID
AND t1.InsttNo = t2.InsttNo;
DELETE t2
FROM
dbo.TableNo2 AS t2
WHERE
NOT EXISTS
(
SELECT 1
FROM dbo.TableNo1 AS t1
WHERE t1.SalesInvoiceID = t2.SalesInvoiceID
AND t1.InsttNo = t2.InsttNo
);
CREATE TABLE #Table1 (New_ID INT IDENTITY (1,1) PRIMARY KEY,SalesInvoiceID
INT,InsttNo INT,PaymentDate DATE,New_Amount INT )
CREATE TABLE #Table2 (New_ID INT IDENTITY (1,1) PRIMARY KEY,Instt_ID INT,
SalesInvoiceID INT,InsttNo INT,DueDate DATE,PaymentDate DATE,Amount INT,Status
VARCHAR(20))
INSERT INTO #Table1 (SalesInvoiceID,InsttNo,PaymentDate,New_Amount) VALUES (30
,1,'2019-05-02','12000')
INSERT INTO #Table1 (SalesInvoiceID,InsttNo,PaymentDate,New_Amount) VALUES (30
,2,'2019-06-02','12000')
INSERT INTO #Table1 (SalesInvoiceID,InsttNo,PaymentDate,New_Amount) VALUES (30
,3,'2019-09-02','4000')
INSERT INTO #Table1 (SalesInvoiceID,InsttNo,PaymentDate,New_Amount) VALUES (30
,4,'2019-12-02','4000')
INSERT INTO #Table2
(Instt_ID,SalesInvoiceID,InsttNo,DueDate,PaymentDate,Amount,Status) VALUES
(51,30,1,'2019-05-02',NULL,0,'Up-Coming')
INSERT INTO #Table2
(Instt_ID,SalesInvoiceID,InsttNo,DueDate,PaymentDate,Amount,Status) VALUES
(52,30,2,'2019-06-02',NULL,0,'Up-Coming')
INSERT INTO #Table2
(Instt_ID,SalesInvoiceID,InsttNo,DueDate,PaymentDate,Amount,Status) VALUES
(53,30,3,'2019-07-02',NULL,0,'Up-Coming')
INSERT INTO #Table2
(Instt_ID,SalesInvoiceID,InsttNo,DueDate,PaymentDate,Amount,Status) VALUES
(54,30,4,'2019-08-02',NULL,0,'Up-Coming')
INSERT INTO #Table2
(Instt_ID,SalesInvoiceID,InsttNo,DueDate,PaymentDate,Amount,Status) VALUES
(55,30,5,'2019-09-02',NULL,0,'Up-Coming')
INSERT INTO #Table2
(Instt_ID,SalesInvoiceID,InsttNo,DueDate,PaymentDate,Amount,Status) VALUES
(56,30,6,'2019-10-02',NULL,0,'Up-Coming')
INSERT INTO #Table2
(Instt_ID,SalesInvoiceID,InsttNo,DueDate,PaymentDate,Amount,Status) VALUES
(57,30,7,'2019-11-02',NULL,0,'Up-Coming')
INSERT INTO #Table2
(Instt_ID,SalesInvoiceID,InsttNo,DueDate,PaymentDate,Amount,Status) VALUES
(58,30,8,'2019-12-02',NULL,0,'Up-Coming')
SELECT
T2.Instt_ID
,T1.SalesInvoiceID
,T1.InsttNo
,T1.PaymentDate DueDate
,T2.PaymentDate
,T2.Amount
,T2.Status
FROM #Table1 t1
INNER JOIN #Table2 T2 ON t1.New_ID = t2.New_ID
DROP TABLE #Table1,#Table2
I want to create a report which aggregates the number of activities per customer per week.
If there has been no activites on that customer for a given week, 0 should be displayed (i.e week 3 and 4 in the sample below)
CUSTOMER | #ACTIVITIES | WEEKNUMBER
A | 4 | 1
A | 2 | 2
A | 0 | 3
A | 0 | 4
A | 1 | 5
B ...
C ...
The problem is that if there are no activities there is no data to report on and therefor week 3 and 4 in the sample below is not in the report.
What is the "best" way to solve this?
Try this:
DECLARE #YourTable table (CUSTOMER char(1), ACTIVITIES int, WEEKNUMBER int)
INSERT #YourTable VALUES ('A' , 4 , 1)
INSERT #YourTable VALUES ('A' , 2 , 2)
INSERT #YourTable VALUES ('A' , 0 , 3)
INSERT #YourTable VALUES ('A' , 0 , 4)
INSERT #YourTable VALUES ('A' , 1 , 5)
INSERT #YourTable VALUES ('B' , 5 , 3)
INSERT #YourTable VALUES ('C' , 2 , 4)
DECLARE #StartNumber int
,#EndNumber int
SELECT #StartNumber=1
,#EndNumber=5
;WITH AllNumbers AS
(
SELECT #StartNumber AS Number
UNION ALL
SELECT Number+1
FROM AllNumbers
WHERE Number<#EndNumber
)
, AllCustomers AS
(
SELECT DISTINCT CUSTOMER FROM #YourTable
)
SELECT
n.Number AS WEEKNUMBER, c.CUSTOMER, CASE WHEN y.Customer IS NULL THEN 0 ELSE y.ACTIVITIES END AS ACTIVITIES
FROM AllNumbers n
CROSS JOIN AllCustomers c
LEFT OUTER JOIN #YourTable y ON n.Number=y.WEEKNUMBER AND c.CUSTOMER=y.CUSTOMER
--OPTION (MAXRECURSION 500)
OUTPUT:
WEEKNUMBER CUSTOMER ACTIVITIES
----------- -------- -----------
1 A 4
1 B 0
1 C 0
2 A 2
2 B 0
2 C 0
3 A 0
3 B 5
3 C 0
4 A 0
4 B 0
4 C 2
5 A 1
5 B 0
5 C 0
(15 row(s) affected)
I use a CTE to build a Numbers table, but you could build a permanent one look at this question: What is the best way to create and populate a numbers table?. You could Write the Query without a CTE (same results as above):
SELECT
n.Number AS WEEKNUMBER, c.CUSTOMER, CASE WHEN y.Customer IS NULL THEN 0 ELSE y.ACTIVITIES END AS ACTIVITIES
FROM Numbers n
CROSS JOIN (SELECT DISTINCT
CUSTOMER
FROM #YourTable
) c
LEFT OUTER JOIN #YourTable y ON n.Number=y.WEEKNUMBER AND c.CUSTOMER=y.CUSTOMER
WHERE n.Number>=1 AND n.Number<=5
ORDER BY n.Number,c.CUSTOMER
Keep a table of time periods separately, and then outer left join the activities to it.
Like:
select *
from ReportingPeriod as p
left join Activities as a on a.ReportingPeriodId = p.ReportingPeriodId;
Refresh my memory. I can't recall how to join tuples (a,b) and (c) to produce (a,b)*(c). For example:
n
---
0
1
2
And
site_id value
----------- -------------
1 a
1 b
2 c
I'd like to end up with:
site_id value n
----------- -------------- --
1 a 0
1 a 1
1 a 2
1 b 0
1 b 1
1 b 2
2 c 0
2 c 1
2 c 2
How can I achieve this?
That's called a CROSS JOIN, also known as the Cartesian product.
SELECT *
FROM Table1
CROSS JOIN Table2
You can also do it without the JOIN keyword just by using a comma:
SELECT * FROM Table1, Table2
Here's full test code you can use to verify that it works:
CREATE TABLE Table1 (n int NOT NULL);
INSERT INTO Table1 (n) VALUES
(0),
(1),
(2);
CREATE TABLE Table2 (site_id int NOT NULL, value nvarchar(100) NOT NULL);
INSERT INTO Table2 (site_id, value) VALUES
(1, 'a'),
(1, 'b'),
(2, 'c');
SELECT Table2.site_id, Table2.value, Table1.n FROM Table1, Table2
Results:
site_id value n
1 a 0
1 a 1
1 a 2
1 b 0
1 b 1
1 b 2
2 c 0
2 c 1
2 c 2
Do a CROSS JOIN
You can try
Select *
FROM table1, table2