Calculate volumes based on date











up vote
1
down vote

favorite












I have this MariaDB table which I would like to use for bar chart:



CREATE TABLE `payment_transaction_daily_facts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date DEFAULT NULL,
`year` int(11) DEFAULT NULL,
`month` int(11) DEFAULT NULL,
`week` int(11) DEFAULT NULL,
`day` int(11) DEFAULT NULL,
`volume` int(11) DEFAULT NULL,
`count` int(11) DEFAULT NULL,
'created_at' date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;


In my example SQL query I have single column for Date. How I can calculate the volumes per day for last 10 days when I have split date, year, month, week and day into different columns?



The final result should be for example:



Date       | Amount| Number of transactions per day |
11-11-2018 | 30 | 3 |
11-12-2018 | 230 | 13 |


I tried this:



SELECT SUM(amount) AS sum_volume, COUNT(*) AS sum_Transactions
WHERE (created_at BETWEEN '2018-11-07' AND '2018-11-08')
GROUP BY DATE(created_at)


I want to return the generated data using DTO:



public class DashboardDTO {

private Date date;

private int sum_volume;

private int sum_Transactions;

... getters and setters
}


Rest controller:



@RestController
@RequestMapping("/dashboard")
public class DashboardController {

private static final Logger LOG = LoggerFactory.getLogger(DashboardController.class);

@Autowired
private DashboardRepository dashboardRepository;

@Autowired
private PaymentTransactionsDailyFactsMapper mapper;

@GetMapping("/volumes")
public ResponseEntity<List<DashboardDTO>> getProcessingVolumes(@PathVariable String start_date, @PathVariable String end_date) {
List<DashboardDTO> list = StreamSupport.stream(dashboardRepository.findPaymentTransactionsDailyFacts(start_date, end_date).spliterator(), false)
.map(mapper::toDTO)
.collect(Collectors.toList());
return ResponseEntity.ok(list);
}
}


JPA query:



public List<PaymentTransactionsDailyFacts> findPaymentTransactionsDailyFacts(LocalDateTime start_date, LocalDateTime end_date) {

String hql = "SELECT SUM(amount) AS sum_volume, COUNT(*) AS sum_Transactions " +
" WHERE (created_at BETWEEN :start_date AND :end_date )" +
" GROUP BY DATE(created_at)";

TypedQuery<PaymentTransactionsDailyFacts> query = entityManager.createQuery(hql,
PaymentTransactionsDailyFacts.class).setParameter("start_date", start_date).setParameter("end_date", end_date);
List<PaymentTransactionsDailyFacts> data = query.getResultList();
return data;
}


How should I implement the query properly?



When I receive start_date and end_date as String from Angular how should I convert it into LocaDateTime?










share|improve this question
























  • Thanks, I added it.
    – Peter Penzov
    Nov 7 at 21:00










  • The date column will look like '2018-11-07'. If Angular mangles it, take Angular out of the way.
    – Rick James
    Nov 7 at 21:09










  • What do you mean by take Angular out of the way?
    – Peter Penzov
    Nov 7 at 21:26






  • 1




    You have way too much information and unnecessary code and multiple questions (how to query, how to convert dates). Please MCVE.
    – K.Nicholas
    Nov 9 at 1:51










  • Can you paste some working example so I can rate it, please?
    – Peter Penzov
    Nov 9 at 7:52















up vote
1
down vote

favorite












I have this MariaDB table which I would like to use for bar chart:



CREATE TABLE `payment_transaction_daily_facts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date DEFAULT NULL,
`year` int(11) DEFAULT NULL,
`month` int(11) DEFAULT NULL,
`week` int(11) DEFAULT NULL,
`day` int(11) DEFAULT NULL,
`volume` int(11) DEFAULT NULL,
`count` int(11) DEFAULT NULL,
'created_at' date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;


In my example SQL query I have single column for Date. How I can calculate the volumes per day for last 10 days when I have split date, year, month, week and day into different columns?



The final result should be for example:



Date       | Amount| Number of transactions per day |
11-11-2018 | 30 | 3 |
11-12-2018 | 230 | 13 |


I tried this:



SELECT SUM(amount) AS sum_volume, COUNT(*) AS sum_Transactions
WHERE (created_at BETWEEN '2018-11-07' AND '2018-11-08')
GROUP BY DATE(created_at)


I want to return the generated data using DTO:



public class DashboardDTO {

private Date date;

private int sum_volume;

private int sum_Transactions;

... getters and setters
}


Rest controller:



@RestController
@RequestMapping("/dashboard")
public class DashboardController {

private static final Logger LOG = LoggerFactory.getLogger(DashboardController.class);

@Autowired
private DashboardRepository dashboardRepository;

@Autowired
private PaymentTransactionsDailyFactsMapper mapper;

@GetMapping("/volumes")
public ResponseEntity<List<DashboardDTO>> getProcessingVolumes(@PathVariable String start_date, @PathVariable String end_date) {
List<DashboardDTO> list = StreamSupport.stream(dashboardRepository.findPaymentTransactionsDailyFacts(start_date, end_date).spliterator(), false)
.map(mapper::toDTO)
.collect(Collectors.toList());
return ResponseEntity.ok(list);
}
}


JPA query:



public List<PaymentTransactionsDailyFacts> findPaymentTransactionsDailyFacts(LocalDateTime start_date, LocalDateTime end_date) {

String hql = "SELECT SUM(amount) AS sum_volume, COUNT(*) AS sum_Transactions " +
" WHERE (created_at BETWEEN :start_date AND :end_date )" +
" GROUP BY DATE(created_at)";

TypedQuery<PaymentTransactionsDailyFacts> query = entityManager.createQuery(hql,
PaymentTransactionsDailyFacts.class).setParameter("start_date", start_date).setParameter("end_date", end_date);
List<PaymentTransactionsDailyFacts> data = query.getResultList();
return data;
}


How should I implement the query properly?



When I receive start_date and end_date as String from Angular how should I convert it into LocaDateTime?










share|improve this question
























  • Thanks, I added it.
    – Peter Penzov
    Nov 7 at 21:00










  • The date column will look like '2018-11-07'. If Angular mangles it, take Angular out of the way.
    – Rick James
    Nov 7 at 21:09










  • What do you mean by take Angular out of the way?
    – Peter Penzov
    Nov 7 at 21:26






  • 1




    You have way too much information and unnecessary code and multiple questions (how to query, how to convert dates). Please MCVE.
    – K.Nicholas
    Nov 9 at 1:51










  • Can you paste some working example so I can rate it, please?
    – Peter Penzov
    Nov 9 at 7:52













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I have this MariaDB table which I would like to use for bar chart:



CREATE TABLE `payment_transaction_daily_facts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date DEFAULT NULL,
`year` int(11) DEFAULT NULL,
`month` int(11) DEFAULT NULL,
`week` int(11) DEFAULT NULL,
`day` int(11) DEFAULT NULL,
`volume` int(11) DEFAULT NULL,
`count` int(11) DEFAULT NULL,
'created_at' date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;


In my example SQL query I have single column for Date. How I can calculate the volumes per day for last 10 days when I have split date, year, month, week and day into different columns?



The final result should be for example:



Date       | Amount| Number of transactions per day |
11-11-2018 | 30 | 3 |
11-12-2018 | 230 | 13 |


I tried this:



SELECT SUM(amount) AS sum_volume, COUNT(*) AS sum_Transactions
WHERE (created_at BETWEEN '2018-11-07' AND '2018-11-08')
GROUP BY DATE(created_at)


I want to return the generated data using DTO:



public class DashboardDTO {

private Date date;

private int sum_volume;

private int sum_Transactions;

... getters and setters
}


Rest controller:



@RestController
@RequestMapping("/dashboard")
public class DashboardController {

private static final Logger LOG = LoggerFactory.getLogger(DashboardController.class);

@Autowired
private DashboardRepository dashboardRepository;

@Autowired
private PaymentTransactionsDailyFactsMapper mapper;

@GetMapping("/volumes")
public ResponseEntity<List<DashboardDTO>> getProcessingVolumes(@PathVariable String start_date, @PathVariable String end_date) {
List<DashboardDTO> list = StreamSupport.stream(dashboardRepository.findPaymentTransactionsDailyFacts(start_date, end_date).spliterator(), false)
.map(mapper::toDTO)
.collect(Collectors.toList());
return ResponseEntity.ok(list);
}
}


JPA query:



public List<PaymentTransactionsDailyFacts> findPaymentTransactionsDailyFacts(LocalDateTime start_date, LocalDateTime end_date) {

String hql = "SELECT SUM(amount) AS sum_volume, COUNT(*) AS sum_Transactions " +
" WHERE (created_at BETWEEN :start_date AND :end_date )" +
" GROUP BY DATE(created_at)";

TypedQuery<PaymentTransactionsDailyFacts> query = entityManager.createQuery(hql,
PaymentTransactionsDailyFacts.class).setParameter("start_date", start_date).setParameter("end_date", end_date);
List<PaymentTransactionsDailyFacts> data = query.getResultList();
return data;
}


How should I implement the query properly?



When I receive start_date and end_date as String from Angular how should I convert it into LocaDateTime?










share|improve this question















I have this MariaDB table which I would like to use for bar chart:



CREATE TABLE `payment_transaction_daily_facts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date DEFAULT NULL,
`year` int(11) DEFAULT NULL,
`month` int(11) DEFAULT NULL,
`week` int(11) DEFAULT NULL,
`day` int(11) DEFAULT NULL,
`volume` int(11) DEFAULT NULL,
`count` int(11) DEFAULT NULL,
'created_at' date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;


In my example SQL query I have single column for Date. How I can calculate the volumes per day for last 10 days when I have split date, year, month, week and day into different columns?



The final result should be for example:



Date       | Amount| Number of transactions per day |
11-11-2018 | 30 | 3 |
11-12-2018 | 230 | 13 |


I tried this:



SELECT SUM(amount) AS sum_volume, COUNT(*) AS sum_Transactions
WHERE (created_at BETWEEN '2018-11-07' AND '2018-11-08')
GROUP BY DATE(created_at)


I want to return the generated data using DTO:



public class DashboardDTO {

private Date date;

private int sum_volume;

private int sum_Transactions;

... getters and setters
}


Rest controller:



@RestController
@RequestMapping("/dashboard")
public class DashboardController {

private static final Logger LOG = LoggerFactory.getLogger(DashboardController.class);

@Autowired
private DashboardRepository dashboardRepository;

@Autowired
private PaymentTransactionsDailyFactsMapper mapper;

@GetMapping("/volumes")
public ResponseEntity<List<DashboardDTO>> getProcessingVolumes(@PathVariable String start_date, @PathVariable String end_date) {
List<DashboardDTO> list = StreamSupport.stream(dashboardRepository.findPaymentTransactionsDailyFacts(start_date, end_date).spliterator(), false)
.map(mapper::toDTO)
.collect(Collectors.toList());
return ResponseEntity.ok(list);
}
}


JPA query:



public List<PaymentTransactionsDailyFacts> findPaymentTransactionsDailyFacts(LocalDateTime start_date, LocalDateTime end_date) {

String hql = "SELECT SUM(amount) AS sum_volume, COUNT(*) AS sum_Transactions " +
" WHERE (created_at BETWEEN :start_date AND :end_date )" +
" GROUP BY DATE(created_at)";

TypedQuery<PaymentTransactionsDailyFacts> query = entityManager.createQuery(hql,
PaymentTransactionsDailyFacts.class).setParameter("start_date", start_date).setParameter("end_date", end_date);
List<PaymentTransactionsDailyFacts> data = query.getResultList();
return data;
}


How should I implement the query properly?



When I receive start_date and end_date as String from Angular how should I convert it into LocaDateTime?







sql spring spring-boot jpa mariadb






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 7 at 20:59

























asked Nov 7 at 20:52









Peter Penzov

4558177371




4558177371












  • Thanks, I added it.
    – Peter Penzov
    Nov 7 at 21:00










  • The date column will look like '2018-11-07'. If Angular mangles it, take Angular out of the way.
    – Rick James
    Nov 7 at 21:09










  • What do you mean by take Angular out of the way?
    – Peter Penzov
    Nov 7 at 21:26






  • 1




    You have way too much information and unnecessary code and multiple questions (how to query, how to convert dates). Please MCVE.
    – K.Nicholas
    Nov 9 at 1:51










  • Can you paste some working example so I can rate it, please?
    – Peter Penzov
    Nov 9 at 7:52


















  • Thanks, I added it.
    – Peter Penzov
    Nov 7 at 21:00










  • The date column will look like '2018-11-07'. If Angular mangles it, take Angular out of the way.
    – Rick James
    Nov 7 at 21:09










  • What do you mean by take Angular out of the way?
    – Peter Penzov
    Nov 7 at 21:26






  • 1




    You have way too much information and unnecessary code and multiple questions (how to query, how to convert dates). Please MCVE.
    – K.Nicholas
    Nov 9 at 1:51










  • Can you paste some working example so I can rate it, please?
    – Peter Penzov
    Nov 9 at 7:52
















Thanks, I added it.
– Peter Penzov
Nov 7 at 21:00




Thanks, I added it.
– Peter Penzov
Nov 7 at 21:00












The date column will look like '2018-11-07'. If Angular mangles it, take Angular out of the way.
– Rick James
Nov 7 at 21:09




The date column will look like '2018-11-07'. If Angular mangles it, take Angular out of the way.
– Rick James
Nov 7 at 21:09












What do you mean by take Angular out of the way?
– Peter Penzov
Nov 7 at 21:26




What do you mean by take Angular out of the way?
– Peter Penzov
Nov 7 at 21:26




1




1




You have way too much information and unnecessary code and multiple questions (how to query, how to convert dates). Please MCVE.
– K.Nicholas
Nov 9 at 1:51




You have way too much information and unnecessary code and multiple questions (how to query, how to convert dates). Please MCVE.
– K.Nicholas
Nov 9 at 1:51












Can you paste some working example so I can rate it, please?
– Peter Penzov
Nov 9 at 7:52




Can you paste some working example so I can rate it, please?
– Peter Penzov
Nov 9 at 7:52












1 Answer
1






active

oldest

votes

















up vote
0
down vote













Well, as I commented, time is a dimension in a data warehouse star schema, and I guess period is as well. So you should have two dimension tables, a TimeDim for LocalDate, and a PeriodDim for Period. Then you should have a Fact with the an embeddedId made up of the various dimensions in your schema. Then you would have facts for 1 day periods and facts for 10 day periods. If you insisted on summing facts you have the issue that JPA cannot do a <= or >= comparison against composite keys. Since you are only summing 10 days you could use a in clause to select 10 keys, but again, you should have facts for the periods you need.



@Entity
public class TimeDim {
@Id
private LocalDate localDate;


@Entity
public class PeriodDim {
@Id
private Period period;

// need this too
@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {
@Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}
@Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}

@SuppressWarnings("serial")
@Embeddable
public class DimKey implements Serializable {
private LocalDate localDate;
private Period period;

@Entity
public class Fact {
@EmbeddedId
private DimKey dimKey = new DimKey();
private long amount;


And for example:



tx.begin();

TimeDim td10 = new TimeDim();
td10.setLocalDate(LocalDate.now().minusDays(5));
em.persist(td10);
TimeDim td5 = new TimeDim();
td5.setLocalDate(LocalDate.now().minusDays(10));
em.persist(td5);

PeriodDim pd5 = new PeriodDim();
pd5.setPeriod(Period.ofDays(5));
em.persist(pd5);
PeriodDim pd10 = new PeriodDim();
pd10.setPeriod(Period.ofDays(10));
em.persist(pd10);

Fact f10 = new Fact();
f10.getDimKey().setLocalDate(td10.getLocalDate());
f10.getDimKey().setPeriod(pd10.getPeriod());
f10.setAmount(100);
em.persist(f10);

Fact f51 = new Fact();
f51.getDimKey().setLocalDate(td10.getLocalDate());
f51.getDimKey().setPeriod(pd5.getPeriod());
f51.setAmount(50);
em.persist(f51);

Fact f52 = new Fact();
f52.getDimKey().setLocalDate(td5.getLocalDate());
f52.getDimKey().setPeriod(pd5.getPeriod());
f52.setAmount(50);
em.persist(f52);

tx.commit();

em.clear();
DimKey dk = new DimKey();
dk.setLocalDate(td10.getLocalDate());
dk.setPeriod(pd10.getPeriod());
Fact f = em.createQuery("select f from Fact f where f.dimKey = :dimKey", Fact.class)
.setParameter("dimKey", dk)
.getSingleResult();
System.out.println("From 10 day period: " + f.getAmount());

DimKey dk1 = new DimKey();
dk1.setLocalDate(td10.getLocalDate());
dk1.setPeriod(pd5.getPeriod());
DimKey dk2 = new DimKey();
dk2.setLocalDate(td5.getLocalDate());
dk2.setPeriod(pd5.getPeriod());
Long sum = em.createQuery("select sum(f.amount) from Fact f where f.dimKey in (:dimKey1 , :dimKey2)", Long.class)
.setParameter("dimKey1", dk1)
.setParameter("dimKey2", dk2)
.getSingleResult();
System.out.println("From 2*5 day period: " + sum);





share|improve this answer





















  • Are you sure that we need 2 entities? Can this be archived with one JPA entity?
    – Peter Penzov
    Nov 10 at 11:04










  • The answer is not what can be done, it is what should be done for the typical data warehouse situation. It you had 365 entries, 1 for every day, you would have a table with the year repeated 365 times, 12 months each repeated about 30 times, 52 weeks each repeated about 7 times, etc, etc. In real life there would be many other dimensions such as geo-location, product, customer type and others. The table would quickly become quite large. Look up "star schema" in the internet.
    – K.Nicholas
    Nov 10 at 14:25











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53197631%2fcalculate-volumes-based-on-date%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote













Well, as I commented, time is a dimension in a data warehouse star schema, and I guess period is as well. So you should have two dimension tables, a TimeDim for LocalDate, and a PeriodDim for Period. Then you should have a Fact with the an embeddedId made up of the various dimensions in your schema. Then you would have facts for 1 day periods and facts for 10 day periods. If you insisted on summing facts you have the issue that JPA cannot do a <= or >= comparison against composite keys. Since you are only summing 10 days you could use a in clause to select 10 keys, but again, you should have facts for the periods you need.



@Entity
public class TimeDim {
@Id
private LocalDate localDate;


@Entity
public class PeriodDim {
@Id
private Period period;

// need this too
@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {
@Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}
@Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}

@SuppressWarnings("serial")
@Embeddable
public class DimKey implements Serializable {
private LocalDate localDate;
private Period period;

@Entity
public class Fact {
@EmbeddedId
private DimKey dimKey = new DimKey();
private long amount;


And for example:



tx.begin();

TimeDim td10 = new TimeDim();
td10.setLocalDate(LocalDate.now().minusDays(5));
em.persist(td10);
TimeDim td5 = new TimeDim();
td5.setLocalDate(LocalDate.now().minusDays(10));
em.persist(td5);

PeriodDim pd5 = new PeriodDim();
pd5.setPeriod(Period.ofDays(5));
em.persist(pd5);
PeriodDim pd10 = new PeriodDim();
pd10.setPeriod(Period.ofDays(10));
em.persist(pd10);

Fact f10 = new Fact();
f10.getDimKey().setLocalDate(td10.getLocalDate());
f10.getDimKey().setPeriod(pd10.getPeriod());
f10.setAmount(100);
em.persist(f10);

Fact f51 = new Fact();
f51.getDimKey().setLocalDate(td10.getLocalDate());
f51.getDimKey().setPeriod(pd5.getPeriod());
f51.setAmount(50);
em.persist(f51);

Fact f52 = new Fact();
f52.getDimKey().setLocalDate(td5.getLocalDate());
f52.getDimKey().setPeriod(pd5.getPeriod());
f52.setAmount(50);
em.persist(f52);

tx.commit();

em.clear();
DimKey dk = new DimKey();
dk.setLocalDate(td10.getLocalDate());
dk.setPeriod(pd10.getPeriod());
Fact f = em.createQuery("select f from Fact f where f.dimKey = :dimKey", Fact.class)
.setParameter("dimKey", dk)
.getSingleResult();
System.out.println("From 10 day period: " + f.getAmount());

DimKey dk1 = new DimKey();
dk1.setLocalDate(td10.getLocalDate());
dk1.setPeriod(pd5.getPeriod());
DimKey dk2 = new DimKey();
dk2.setLocalDate(td5.getLocalDate());
dk2.setPeriod(pd5.getPeriod());
Long sum = em.createQuery("select sum(f.amount) from Fact f where f.dimKey in (:dimKey1 , :dimKey2)", Long.class)
.setParameter("dimKey1", dk1)
.setParameter("dimKey2", dk2)
.getSingleResult();
System.out.println("From 2*5 day period: " + sum);





share|improve this answer





















  • Are you sure that we need 2 entities? Can this be archived with one JPA entity?
    – Peter Penzov
    Nov 10 at 11:04










  • The answer is not what can be done, it is what should be done for the typical data warehouse situation. It you had 365 entries, 1 for every day, you would have a table with the year repeated 365 times, 12 months each repeated about 30 times, 52 weeks each repeated about 7 times, etc, etc. In real life there would be many other dimensions such as geo-location, product, customer type and others. The table would quickly become quite large. Look up "star schema" in the internet.
    – K.Nicholas
    Nov 10 at 14:25















up vote
0
down vote













Well, as I commented, time is a dimension in a data warehouse star schema, and I guess period is as well. So you should have two dimension tables, a TimeDim for LocalDate, and a PeriodDim for Period. Then you should have a Fact with the an embeddedId made up of the various dimensions in your schema. Then you would have facts for 1 day periods and facts for 10 day periods. If you insisted on summing facts you have the issue that JPA cannot do a <= or >= comparison against composite keys. Since you are only summing 10 days you could use a in clause to select 10 keys, but again, you should have facts for the periods you need.



@Entity
public class TimeDim {
@Id
private LocalDate localDate;


@Entity
public class PeriodDim {
@Id
private Period period;

// need this too
@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {
@Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}
@Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}

@SuppressWarnings("serial")
@Embeddable
public class DimKey implements Serializable {
private LocalDate localDate;
private Period period;

@Entity
public class Fact {
@EmbeddedId
private DimKey dimKey = new DimKey();
private long amount;


And for example:



tx.begin();

TimeDim td10 = new TimeDim();
td10.setLocalDate(LocalDate.now().minusDays(5));
em.persist(td10);
TimeDim td5 = new TimeDim();
td5.setLocalDate(LocalDate.now().minusDays(10));
em.persist(td5);

PeriodDim pd5 = new PeriodDim();
pd5.setPeriod(Period.ofDays(5));
em.persist(pd5);
PeriodDim pd10 = new PeriodDim();
pd10.setPeriod(Period.ofDays(10));
em.persist(pd10);

Fact f10 = new Fact();
f10.getDimKey().setLocalDate(td10.getLocalDate());
f10.getDimKey().setPeriod(pd10.getPeriod());
f10.setAmount(100);
em.persist(f10);

Fact f51 = new Fact();
f51.getDimKey().setLocalDate(td10.getLocalDate());
f51.getDimKey().setPeriod(pd5.getPeriod());
f51.setAmount(50);
em.persist(f51);

Fact f52 = new Fact();
f52.getDimKey().setLocalDate(td5.getLocalDate());
f52.getDimKey().setPeriod(pd5.getPeriod());
f52.setAmount(50);
em.persist(f52);

tx.commit();

em.clear();
DimKey dk = new DimKey();
dk.setLocalDate(td10.getLocalDate());
dk.setPeriod(pd10.getPeriod());
Fact f = em.createQuery("select f from Fact f where f.dimKey = :dimKey", Fact.class)
.setParameter("dimKey", dk)
.getSingleResult();
System.out.println("From 10 day period: " + f.getAmount());

DimKey dk1 = new DimKey();
dk1.setLocalDate(td10.getLocalDate());
dk1.setPeriod(pd5.getPeriod());
DimKey dk2 = new DimKey();
dk2.setLocalDate(td5.getLocalDate());
dk2.setPeriod(pd5.getPeriod());
Long sum = em.createQuery("select sum(f.amount) from Fact f where f.dimKey in (:dimKey1 , :dimKey2)", Long.class)
.setParameter("dimKey1", dk1)
.setParameter("dimKey2", dk2)
.getSingleResult();
System.out.println("From 2*5 day period: " + sum);





share|improve this answer





















  • Are you sure that we need 2 entities? Can this be archived with one JPA entity?
    – Peter Penzov
    Nov 10 at 11:04










  • The answer is not what can be done, it is what should be done for the typical data warehouse situation. It you had 365 entries, 1 for every day, you would have a table with the year repeated 365 times, 12 months each repeated about 30 times, 52 weeks each repeated about 7 times, etc, etc. In real life there would be many other dimensions such as geo-location, product, customer type and others. The table would quickly become quite large. Look up "star schema" in the internet.
    – K.Nicholas
    Nov 10 at 14:25













up vote
0
down vote










up vote
0
down vote









Well, as I commented, time is a dimension in a data warehouse star schema, and I guess period is as well. So you should have two dimension tables, a TimeDim for LocalDate, and a PeriodDim for Period. Then you should have a Fact with the an embeddedId made up of the various dimensions in your schema. Then you would have facts for 1 day periods and facts for 10 day periods. If you insisted on summing facts you have the issue that JPA cannot do a <= or >= comparison against composite keys. Since you are only summing 10 days you could use a in clause to select 10 keys, but again, you should have facts for the periods you need.



@Entity
public class TimeDim {
@Id
private LocalDate localDate;


@Entity
public class PeriodDim {
@Id
private Period period;

// need this too
@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {
@Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}
@Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}

@SuppressWarnings("serial")
@Embeddable
public class DimKey implements Serializable {
private LocalDate localDate;
private Period period;

@Entity
public class Fact {
@EmbeddedId
private DimKey dimKey = new DimKey();
private long amount;


And for example:



tx.begin();

TimeDim td10 = new TimeDim();
td10.setLocalDate(LocalDate.now().minusDays(5));
em.persist(td10);
TimeDim td5 = new TimeDim();
td5.setLocalDate(LocalDate.now().minusDays(10));
em.persist(td5);

PeriodDim pd5 = new PeriodDim();
pd5.setPeriod(Period.ofDays(5));
em.persist(pd5);
PeriodDim pd10 = new PeriodDim();
pd10.setPeriod(Period.ofDays(10));
em.persist(pd10);

Fact f10 = new Fact();
f10.getDimKey().setLocalDate(td10.getLocalDate());
f10.getDimKey().setPeriod(pd10.getPeriod());
f10.setAmount(100);
em.persist(f10);

Fact f51 = new Fact();
f51.getDimKey().setLocalDate(td10.getLocalDate());
f51.getDimKey().setPeriod(pd5.getPeriod());
f51.setAmount(50);
em.persist(f51);

Fact f52 = new Fact();
f52.getDimKey().setLocalDate(td5.getLocalDate());
f52.getDimKey().setPeriod(pd5.getPeriod());
f52.setAmount(50);
em.persist(f52);

tx.commit();

em.clear();
DimKey dk = new DimKey();
dk.setLocalDate(td10.getLocalDate());
dk.setPeriod(pd10.getPeriod());
Fact f = em.createQuery("select f from Fact f where f.dimKey = :dimKey", Fact.class)
.setParameter("dimKey", dk)
.getSingleResult();
System.out.println("From 10 day period: " + f.getAmount());

DimKey dk1 = new DimKey();
dk1.setLocalDate(td10.getLocalDate());
dk1.setPeriod(pd5.getPeriod());
DimKey dk2 = new DimKey();
dk2.setLocalDate(td5.getLocalDate());
dk2.setPeriod(pd5.getPeriod());
Long sum = em.createQuery("select sum(f.amount) from Fact f where f.dimKey in (:dimKey1 , :dimKey2)", Long.class)
.setParameter("dimKey1", dk1)
.setParameter("dimKey2", dk2)
.getSingleResult();
System.out.println("From 2*5 day period: " + sum);





share|improve this answer












Well, as I commented, time is a dimension in a data warehouse star schema, and I guess period is as well. So you should have two dimension tables, a TimeDim for LocalDate, and a PeriodDim for Period. Then you should have a Fact with the an embeddedId made up of the various dimensions in your schema. Then you would have facts for 1 day periods and facts for 10 day periods. If you insisted on summing facts you have the issue that JPA cannot do a <= or >= comparison against composite keys. Since you are only summing 10 days you could use a in clause to select 10 keys, but again, you should have facts for the periods you need.



@Entity
public class TimeDim {
@Id
private LocalDate localDate;


@Entity
public class PeriodDim {
@Id
private Period period;

// need this too
@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {
@Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}
@Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}

@SuppressWarnings("serial")
@Embeddable
public class DimKey implements Serializable {
private LocalDate localDate;
private Period period;

@Entity
public class Fact {
@EmbeddedId
private DimKey dimKey = new DimKey();
private long amount;


And for example:



tx.begin();

TimeDim td10 = new TimeDim();
td10.setLocalDate(LocalDate.now().minusDays(5));
em.persist(td10);
TimeDim td5 = new TimeDim();
td5.setLocalDate(LocalDate.now().minusDays(10));
em.persist(td5);

PeriodDim pd5 = new PeriodDim();
pd5.setPeriod(Period.ofDays(5));
em.persist(pd5);
PeriodDim pd10 = new PeriodDim();
pd10.setPeriod(Period.ofDays(10));
em.persist(pd10);

Fact f10 = new Fact();
f10.getDimKey().setLocalDate(td10.getLocalDate());
f10.getDimKey().setPeriod(pd10.getPeriod());
f10.setAmount(100);
em.persist(f10);

Fact f51 = new Fact();
f51.getDimKey().setLocalDate(td10.getLocalDate());
f51.getDimKey().setPeriod(pd5.getPeriod());
f51.setAmount(50);
em.persist(f51);

Fact f52 = new Fact();
f52.getDimKey().setLocalDate(td5.getLocalDate());
f52.getDimKey().setPeriod(pd5.getPeriod());
f52.setAmount(50);
em.persist(f52);

tx.commit();

em.clear();
DimKey dk = new DimKey();
dk.setLocalDate(td10.getLocalDate());
dk.setPeriod(pd10.getPeriod());
Fact f = em.createQuery("select f from Fact f where f.dimKey = :dimKey", Fact.class)
.setParameter("dimKey", dk)
.getSingleResult();
System.out.println("From 10 day period: " + f.getAmount());

DimKey dk1 = new DimKey();
dk1.setLocalDate(td10.getLocalDate());
dk1.setPeriod(pd5.getPeriod());
DimKey dk2 = new DimKey();
dk2.setLocalDate(td5.getLocalDate());
dk2.setPeriod(pd5.getPeriod());
Long sum = em.createQuery("select sum(f.amount) from Fact f where f.dimKey in (:dimKey1 , :dimKey2)", Long.class)
.setParameter("dimKey1", dk1)
.setParameter("dimKey2", dk2)
.getSingleResult();
System.out.println("From 2*5 day period: " + sum);






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 10 at 3:03









K.Nicholas

5,09932237




5,09932237












  • Are you sure that we need 2 entities? Can this be archived with one JPA entity?
    – Peter Penzov
    Nov 10 at 11:04










  • The answer is not what can be done, it is what should be done for the typical data warehouse situation. It you had 365 entries, 1 for every day, you would have a table with the year repeated 365 times, 12 months each repeated about 30 times, 52 weeks each repeated about 7 times, etc, etc. In real life there would be many other dimensions such as geo-location, product, customer type and others. The table would quickly become quite large. Look up "star schema" in the internet.
    – K.Nicholas
    Nov 10 at 14:25


















  • Are you sure that we need 2 entities? Can this be archived with one JPA entity?
    – Peter Penzov
    Nov 10 at 11:04










  • The answer is not what can be done, it is what should be done for the typical data warehouse situation. It you had 365 entries, 1 for every day, you would have a table with the year repeated 365 times, 12 months each repeated about 30 times, 52 weeks each repeated about 7 times, etc, etc. In real life there would be many other dimensions such as geo-location, product, customer type and others. The table would quickly become quite large. Look up "star schema" in the internet.
    – K.Nicholas
    Nov 10 at 14:25
















Are you sure that we need 2 entities? Can this be archived with one JPA entity?
– Peter Penzov
Nov 10 at 11:04




Are you sure that we need 2 entities? Can this be archived with one JPA entity?
– Peter Penzov
Nov 10 at 11:04












The answer is not what can be done, it is what should be done for the typical data warehouse situation. It you had 365 entries, 1 for every day, you would have a table with the year repeated 365 times, 12 months each repeated about 30 times, 52 weeks each repeated about 7 times, etc, etc. In real life there would be many other dimensions such as geo-location, product, customer type and others. The table would quickly become quite large. Look up "star schema" in the internet.
– K.Nicholas
Nov 10 at 14:25




The answer is not what can be done, it is what should be done for the typical data warehouse situation. It you had 365 entries, 1 for every day, you would have a table with the year repeated 365 times, 12 months each repeated about 30 times, 52 weeks each repeated about 7 times, etc, etc. In real life there would be many other dimensions such as geo-location, product, customer type and others. The table would quickly become quite large. Look up "star schema" in the internet.
– K.Nicholas
Nov 10 at 14:25


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53197631%2fcalculate-volumes-based-on-date%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Xamarin.form Move up view when keyboard appear

Post-Redirect-Get with Spring WebFlux and Thymeleaf

Anylogic : not able to use stopDelay()