我在名为YEAR1, MONTH1, YEAR2, MONTH2
的表中有INT
的四列TABEL1
。我想为TABLE2
中的每一行在表TABLE1
中插入多行,这些行的列值介于YEAR
和MONTH
之间,并且YEAR
和MONTH
在TABLE1
中。
表1类似于:
ID YEAR1 MONTH1 YEAR2 MONTH2
------------------------------------
1 2010 11 2011 2
2 2012 10 2012 12
Table2应该像:
ID YEAR MONTH
-----------------
1 2010 11
1 2010 12
1 2011 1
1 2011 2
2 2012 10
2 2012 11
2 2012 12
我不知道我应该使用while循环还是只使用select语句。 我写了一个用于插入的函数,但发现无法在用户定义的函数中使用CRUD。
SELECT Calc(ID,YEAR1,YEAR2,MONTH1,MONTH2) FROM Table1
CREATE FUNCTION Calc(@ID INT, @YEAR1 INT, @YEAR2 INT, @PERIOD1 INT, @PERIOD2 INT)
RETURNS TINYINT
AS BEGIN
DECLARE @ID INT
DECLARE @YEAR INT
DECLARE @MONTH INT
SET @YEAR = @YEAR1
SET @MONTH = @MONTH1
WHILE (@YEAR <= @YEAR2)
WHILE (@MONTH <= @MONTH2)
INSERT INTO TABLE2 (ID,YEAR,MONTH)
VALUES (@ID,@YEAR,@MONTH)
SET @MONTH = @MONTH + 1
END
SET @YEAR = @YEAR + 1
END
RETURN 1
END
更新:
MONTH
并非确切月份。实际上是SEASON
,其值为1,2,3,4
。
另一个问题是YEAR
和MONTH
是从波斯日期中提取的,而不是公历日期,而波斯日期被另存为NVARCHAR
在数据库中。
因此,看来我不能在这里使用DATE
函数。
答案 0 :(得分:1)
首先,创建一个 table-valued function
,它根据传递的@ID
为您返回日期
CREATE FUNCTION dbo.GetDates
(
@ID INT
)
RETURNS TABLE
AS
RETURN
(
WITH CTE AS
(
SELECT DATEFROMPARTS(YEAR1, MONTH1, 1) Dates
FROM T
WHERE ID = @ID
UNION ALL
SELECT DATEADD(Month, 1, Dates)
FROM CTE
WHERE DATEADD(Month, 1, Dates) <
(SELECT DATEFROMPARTS(YEAR2, MONTH2, 2) FROM T WHERE ID = @ID)
)
SELECT *
FROM CTE
)
然后只需将其用作(使用CROSS APPLY
来访问ID
列)
SELECT T.ID,
YEAR(Dates) [YEAR],
MONTH(Dates) [MONTH]
FROM T CROSS APPLY dbo.GetDates(ID) TT
返回:
+----+------+-------+
| ID | YEAR | MONTH |
+----+------+-------+
| 1 | 2010 | 11 |
| 1 | 2010 | 12 |
| 1 | 2011 | 1 |
| 1 | 2011 | 2 |
| 2 | 2012 | 10 |
| 2 | 2012 | 11 |
| 2 | 2012 | 12 |
+----+------+-------+
答案 1 :(得分:1)
已经提到了很多不错的选择。我也倾向于使用元素周期表和联接。一种方法可能是以下一种:
USE TEMPDB
CREATE TABLE #Y (YY INT)
INSERT INTO #Y VALUES (2000), (2001), (2002), (2003), (2004),
(2005), (2006), (2007), (2008), (2009),
(2010), (2011), (2012), (2013), (2014),
(2015), (2016), (2017), (2018), (2019)
CREATE Table #M (Mnth INT)
INSERT INTO #M VALUES (1), (2), (3), (4), (5), (6),
(7), (8), (9), (10), (11), (12)
SELECT *, CASE WHEN Mnth < 10 THEN CAST (YY AS CHAR (4)) + '0' + CAST (Mnth AS CHAR (2))
ELSE CAST (YY AS CHAR (4)) + CAST (Mnth AS CHAR (2)) END AS Combined
INTO #Period
FROM #Y
CROSS JOIN #M
SELECT * FROM #Period
CREATE TABLE TABLE1 (ID INT, YEAR1 INT, MONTH1 INT, Combined1 CHAR (6), YEAR2 INT, MONTH2 INT, Combined2 CHAR (6))
INSERT INTO TABLE1 VALUES (1, 2010, 11, '201011', 2011, 2, '201102'), (2, 2012, 10, '201210', 2012, 12, '201212')
SELECT * FROM TABLE1
SELECT T.ID, P.YY, P.Mnth
FROM #Period AS P
INNER JOIN TABLE1 AS T ON P.Combined BETWEEN Combined1 AND Combined2
ORDER BY 1, 2
--DROP TABLE #M, #Period, #Y, TABLE1
答案 2 :(得分:1)
如果使用a Calendar table,查询将变得很简单。日历表包含每个日期一行,例如未来100年,其中分别包含年,月,日,年中的某天,周号以及其他可能需要的字段。索引各个字段可以按年,月等进行快速查找。
一旦有了这样一个表,您只需要返回位于 private long randomAndroidColor;
randomAndroidColor = getIntent().getLongExtra(EXTRA_COLOR, 0L);
getSupportActionBar().setBackgroundDrawable(
new ColorDrawable(Color.parseColor(String.valueOf(randomAndroidColor)))
);
和year
值之间的不同的month
和From
日历值。如果范围值是日期,则可以输入:
To
由于我们需要比较年月,因此事情变得有些复杂:
select distinct id,Calendar.year,Calendar.Month
from #table1 inner join DimDate as Calendar
on Calendar.Date between #table1.StartDate and #table1.EndDate
order by Calendar.Year,Calendar.Month
如果源表和日历表具有“年月”列,例如YYYYMM格式,则可以大大简化查询。这可能是实际的列,也可能是索引所涵盖的已计算和持久的列:
CREATE TABLE #Table1 (
ID int,
YEAR1 int,
MONTH1 int,
YEAR2 int,
MONTH2 int
)
INSERT INTO #Table1
(ID, YEAR1, MONTH1, YEAR2, MONTH2)
VALUES
(1, 2010, 11, 2011, 2),
(2, 2012, 10, 2012, 12)
select distinct id,Calendar.year,Calendar.Month
from #table1 inner join DimDate as Calendar on
(#table1.YEAR1=Calendar.Year and #Table1.Month1<=Calendar.Month
and (#table1.YEAR2>Calendar.Year or #Table1.Month2>=Calendar.Month)
)
or
(#table1.YEAR1<Calendar.Year and (#table1.YEAR2>Calendar.Year
or (#table1.YEAR2=Calendar.Year
and #Table1.Month2>=Calendar.Month)))
order by Calendar.Year,Calendar.Month
之后,查询变得简单:
CREATE TABLE #Table1 (
ID int,
YEAR1 int,
MONTH1 int,
YEAR2 int,
MONTH2 int ,
YearMonth1 AS YEAR1*100+Month1 persisted,
YearMonth2 as Year2*100+Month2 persisted
)
create index IX_Table1_YearMonth1 on #Table1 (YearMonth1) Include (Year1,Month1)
create index IX_Table1_YearMonth2 on #Table1 (YearMonth2) include (Year2,Month2)
执行计划简单快捷:
答案 3 :(得分:0)
您可以尝试查询
DECLARE @minYear VARCHAR(10),
@minMonth VARCHAR(10),
@maxYear VARCHAR(10),
@maxMonth VARCHAR(10)
SELECT *
INTO #table1
FROM (SELECT 1 id,
2010 year1,
11 month1,
2011 year2,
2 month2
UNION ALL
SELECT 2 id,
2012 year1,
10 month1,
2012 year2,
12 month2) Table1
SELECT @minYear = Min(year1),
@minMonth = Min(month1),
@maxYear = Max(year2),
@maxMonth = Max(month2)
FROM #table1;
WITH cte
AS (SELECT CONVERT(DATE, @minYear + '-' + @minMonth + '-01') AS dt
UNION ALL
SELECT Dateadd (month, 1, dt) dt
FROM cte
WHERE dt < CONVERT(DATE, @maxYear + '-' + @maxMonth + '-01'))
SELECT id,
Year(dt)[year],
Month(dt) [month]
FROM #table1 Table1
INNER JOIN cte
ON cte.dt BETWEEN CONVERT(DATE, CONVERT (VARCHAR, year1) + '-'
+ CONVERT(VARCHAR, month1) +
'-01') AND
CONVERT(
DATE,
CONVERT(VARCHAR, year2) +
'-'
+ CONVERT(VARCHAR, month2) +
'-01')
答案 4 :(得分:0)
您可以完美地使用UNPIVOT,这是我的提案解决方案
DECLARE @Table1 AS TABLE
(
ID INT,
YEAR1 INT,
MONTH1 INT,
YEAR2 INT,
MONTH2 INT
)
INSERT INTO @Table1 VALUES (1,2010,11,2011,2),(2,2012,10,2012,12)
SELECT ID, [YEAR],[MONTH]
FROM
(
SELECT ID, YEAR1,YEAR2,MONTH1,MONTH2
FROM @Table1
) AS t
UNPIVOT
(
[YEAR] FOR YEARS IN (YEAR1, YEAR2)
) AS up
UNPIVOT
(
[MONTH] FOR MONTHS IN (MONTH1,MONTH2)
) AS um
答案 5 :(得分:0)
一种可能的方法是定义一个表值函数,然后使用此函数:
功能:
CREATE FUNCTION [dbo].[udf_GetMonths] (@year1 int, @month1 int, @year2 int, @month2 int)
RETURNS TABLE
AS
RETURN
(
WITH Months AS
(
SELECT DATEFROMPARTS(@year1, @month1, 1) AS SomeDate
UNION ALL
SELECT DATEADD(month, 1, SomeDate) AS SomeDate
FROM Months
WHERE
(DATEPART(year, SomeDate) < @year2) OR
(DATEPART(month, SomeDate) < @month2)
)
SELECT YEAR(SomeDate) AS [YEAR], MONTH(SomeDate) AS [MONTH]
FROM Months
)
INSERT语句:
-- Table 1
CREATE TABLE #Table1 (
ID int,
YEAR1 int,
MONTH1 int,
YEAR2 int,
MONTH2 int
)
INSERT INTO #Table1
(ID, YEAR1, MONTH1, YEAR2, MONTH2)
VALUES
(1, 2010, 11, 2011, 2),
(2, 2012, 10, 2012, 12)
-- Table 2
CREATE TABLE #Table2 (
ID int,
[YEAR] int,
[MONTH] int
)
-- Insert
INSERT INTO #Table2 (ID, [YEAR], [MONTH])
SELECT t.ID, f.[YEAR], f.[MONTH]
FROM #Table1 t
CROSS APPLY (SELECT * FROM dbo.udf_GetMonths(t.YEAR1, t.MONTH1, t.YEAR2, t.MONTH2)) f
OPTION (MAXRECURSION 0)
插入行:
ID YEAR MONTH
1 2010 11
1 2010 12
1 2011 1
1 2011 2
2 2012 10
2 2012 11
2 2012 12